您的位置:首页 > 其它

2016长乐夏令营 Day6

2016-07-15 19:58 309 查看
T1:

远古农场数小于等于10,意味着我们可以枚举远古农场的选择方案,这样原图中的所有点就被分为一定不能新建农场的点和可能可以新建农场的点。为了让新建的农场数量最大,农场显然是1*1最好,然后农场不能相邻,于是将可能可以建农场的点染成黑白两色(第一发代码在这里停止,直接贪心,居然过6个点。。强),就成了二分图,需要在里面找出一个最大独立子集,总点数-最大匹配就是了(Dicnic)又炸一波

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;

const int maxn = 20;
const int dx[4] = {0,1,0,-1};
const int dy[4] = {1,0,-1,0};
const int S = 0;
const int T = 200;
const int INF = ~0U>>1;

struct Point{
int x,y;
Point(int _x = 0,int _y = 0) {x = _x; y = _y;}
};

struct E{
int from,to,cap,flow;
E(int _from = 0,int _to = 0,int _cap = 0,int _flow = 0) {from = _from; to = _to; cap = _cap; flow = _flow;}
}edgs[10000];

char p[maxn][maxn];
int t,n,m,ans,cnt,now,sum,tail,cur[210],que[210],vis[210],
L[210],Num[maxn][maxn],q[maxn][maxn],Use[maxn],P[maxn][maxn];
bool arg[maxn][maxn],b[maxn];

vector <int> v[110];
queue <Point> Q;
queue <int> Qu;

int Draw(int i,int j)
{
q[i][j] = 1; Q.push(Point(i,j));
while (!Q.empty()) {
Point k = Q.front(); Q.pop(); ++sum;
for (int l = 0; l < 4; l++) {
int xx = k.x + dx[l];
int yy = k.y + dy[l];
if (xx < 0 || xx == n || yy < 0 || yy == m) continue;
if (P[xx][yy] == cnt || q[xx][yy] != -1) continue;
q[xx][yy] = q[k.x][k.y] ^ 1;
Q.push(Point(xx,yy));
}
}
}

bool PreJudge()
{
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
if (Use[i] == cnt && Use[j] == cnt && arg[i][j])
return 0;
return 1;
}

void Work()
{
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if ('0' <= p[i][j] && p[i][j] <= '9') {
P[i][j] = cnt;
if (Use[p[i][j] - '0'] == cnt)
for (int l = 0; l < 4; l++) {
int xx = i + dx[l];
int yy = j + dy[l];
if (xx < 0 || xx == n || yy < 0 || yy == m) continue;
P[xx][yy] = cnt;
}
}
}

void Add(int from,int to,int w)
{
v[from].push_back(tail); edgs[tail++] = E(from,to,w,0);
v[to].push_back(tail); edgs[tail++] = E(to,from,0,0);
}

bool BFS()
{
++cnt; L[S] = 1;
Qu.push(S); vis[S] = cnt;
while (!Qu.empty()) {
int k = Qu.front(); Qu.pop();
for (int i = 0; i < v[k].size(); i++) {
E e = edgs[v[k][i]];
if (e.cap == e.flow) continue;
if (vis[e.to] == cnt) continue;
vis[e.to] = cnt;
L[e.to] = L[k] + 1;
Qu.push(e.to);
}
}
return vis[T] == cnt;
}

int Dicnic(int x,int a)
{
if (x == T) return a;
int flow = 0;
for (int &i = cur[x]; i < v[x].size(); i++) {
E &e = edgs[v[x][i]];
if (e.cap == e.flow) continue;
if (L[x] + 1 != L[e.to]) continue;
int F = Dicnic(e.to,min(a,e.cap - e.flow));
if (F > 0) {
e.flow += F;
edgs[v[x][i]^1].flow -= F;
flow += F;
a -= F;
if (!a) return flow;
}
}
return flow;
}

void Solve(int x)
{
int po = 0; ++cnt; now = sum = tail = 0;
for (; x; x >>= 1) {
if (x & 1) {
if (!b[po]) return;
Use[po] = cnt; ++now;
}
++po;
}
bool flag = PreJudge();
if (!flag) return;
Work();

for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
q[i][j] = -1;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (P[i][j] != cnt && q[i][j] == -1)
Draw(i,j);
int Tail = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (q[i][j] != -1) {
if (q[i][j]) {
Add(S,Num[i][j],1);
for (int l = 0; l < 4; l++) {
int xx = i + dx[l];
int yy = j + dy[l];
if (xx < 0 || xx == n || yy < 0 || yy == m) continue;
if (!q[xx][yy]) Add(Num[i][j],Num[xx][yy],1);
}
}
else Add(Num[i][j],T,1);
que[++Tail] = Num[i][j];
}
int flow = 0;
while (BFS()) {
for (int i = 1; i <= Tail; i++) cur[que[i]] = 0; cur[S] = cur[T] = 0;
flow += Dicnic(S,INF);
}
for (int i = 1; i <= Tail; i++) v[que[i]].clear();
v[S].clear(); v[T].clear();
ans = max(ans,sum - flow + now);
}

void PRE()
{
scanf("%d%d",&n,&m); ans = 0;
for (int i = 0; i < 10; i++) b[i] = 0;
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
arg[i][j] = 0;
for (int i = 0; i < n; i++) scanf("%s",p[i]);
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if ('0' <= p[i][j] && p[i][j] <= '9') {
b[p[i][j] - '0'] = 1;
for (int l = 0; l < 4; l++) {
int xx = i + dx[l];
int yy = j + dy[l];
if (xx < 0 || xx == n || yy < 0 || yy == m) continue;
if (p[xx][yy] != p[i][j] && p[xx][yy] != '.')
arg[p[i][j]-'0'][p[xx][yy]-'0'] = 1;
}
}
int SUM = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
Num[i][j] = ++SUM;
}

int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("minecraft.in","r",stdin);
freopen("minecraft.out","w",stdout);
#endif

cin >> t;

for (int Case = 1; Case <= t; Case++) {
PRE();
for (int i = 0; i < (1<<10); i++)
Solve(i);
printf("Case #%d: %d\n",Case,ans);
}
return 0;
}




T2:
f[a][b][c][d][i][j] 表示各种花色各选了a,b,c,d张,王的状态是i,j(0表示还没选),到当前目标的期望步数

转移见代码,特别注意的是王的转移就枚举后面的方案,贪心一下就好

转移的方式,就记忆化搜索吧

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;

typedef double DB;

DB f[16][16][16][16][5][5];
int T,cnt,A,B,C,D,vis[16][16][16][16][5][5];

DB DP(int a,int b,int c,int d,int i,int j)
{
if (vis[a][c][d][i][j] == cnt) return f[a][b][c][d][i][j] + 1.00;
int a1 = a,b1 = b,c1 = c,d1 = d;
if (i == 1) ++a1; if (j == 1) ++a1;
if (i == 2) ++b1; if (j == 2) ++b1;
if (i == 3) ++c1; if (j == 3) ++c1;
if (i == 4) ++d1; if (j == 4) ++d1;
if (a1 >= A && b1 >= B && c1 >= C && d1 >= D) return 1.00;
f[a][b][c][d][i][j] = 0.00;
vis[a][b][c][d][i][j] = cnt;
int res = 54 - a - b - c - d;
if (i) --res; if (j) --res; DB R = res;
DB &F = f[a][b][c][d][i][j];
if (a < 13) F += (DB)(13-a)/R*DP(a+1,b,c,d,i,j);
if (b < 13) F += (DB)(13-b)/R*DP(a,b+1,c,d,i,j);
if (c < 13) F += (DB)(13-c)/R*DP(a,b,c+1,d,i,j);
if (d < 13) F += (DB)(13-d)/R*DP(a,b,c,d+1,i,j);
DB X = 1.00,Min = 1E16;
if (!i) {
for (int k = 1; k <= 4; k++) Min = min(Min,DP(a,b,c,d,k,j));
F += X/R*Min; Min = 1E16;
}
if (!j) {
for (int k = 1; k <= 4; k++) Min = min(Min,DP(a,b,c,d,i,k));
F += X/R*Min;
}
return f[a][b][c][d][i][j] + 1.00;
}

int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("card.in","r",stdin);
freopen("card.out","w",stdout);
#endif

DP(0,0,0,0,0,0);

cin >> T;
for (int Case = 1; Case <= T; Case++) {
scanf("%d%d%d%d",&A,&B,&C,&D);
int K = 0; DB ans = 0;
if (A - 13 >= 0) K += A - 13;
if (B - 13 >= 0) K += B - 13;
if (C - 13 >= 0) K += C - 13;
if (D - 13 >= 0) K += D - 13;
if (K > 2) {printf("Case %d: -1\n",Case); continue;}
++cnt; DP(0,0,0,0,0,0);
printf("Case %d: %.7f\n",Case,f[0][0][0][0][0][0]);
}
return 0;
}


这大概是个DAG上的dp,反正。。。能找到的只有当前起点到当前终点的方案了



[b]T3:


想让距离和最小,显然点与点要按顺序连起来,然后,距离和最小时距离平方和最小,这东西是个二次函数,三分吧
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;

typedef double DB;
const int maxn = 1E4 + 10;

DB a[maxn*2];
int n;

DB Work(DB now)
{
DB ret,po; ret = po = 0.00;
for (int i = 1; i <= 2*n; i++) {
po += 1.00;
DB x = now + po - a[i]; //x -= a[i];
ret += sqrt(1.00 + x*x);
}
return ret;
}

int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#else
freopen("seg.in","r",stdin);
freopen("seg.out","w",stdout);
#endif

cin >> n;
for (int i = 1; i <= 2*n; i++) {
int x; scanf("%d",&x);
a[i] = x*1.00;
}
sort(a + 1,a + 2*n + 1);
DB L,R; L = -1E9; R = 1E9;
for (int i = 0; i < 100; i++) {
DB T = (R-L)/3.00;
DB mid1 = L + T;
DB mid2 = L + T*2.00;
DB ret1 = Work(mid1);
DB ret2 = Work(mid2);
if (ret1 > ret2) L = mid1;
else R = mid2;
}
printf("%.13f",Work(L));
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: