2016长乐夏令营 Day6

57 篇文章 0 订阅
14 篇文章 0 订阅

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][b][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,反正。。。能找到的只有当前起点到当前终点的方案了


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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值