「FJ2015集训」贪吃蛇
最近lwher迷上了贪吃蛇游戏,在玩了几天却从未占满全地图的情况下,他不得不承认自己是一个弱菜,只能改去开发一款更弱的贪吃蛇游戏。
在开发的过程中,lwher脑洞大开,搞了一个多条蛇的模式。但由于这种模式太难操作,于是他只好改变游戏的玩法,稍微变化一下游戏目标。
新的游戏是这样的:
一些蛇覆盖了一个网格。每个格子要么是一个障碍物,要么是蛇的一部分。每条蛇占据了一条折线(拐角处只能水平和竖直连接),且只是占据两个格子。蛇与蛇之间不能重叠,蛇也不会与自己重叠。每条蛇还必须满足以下两个条件中的一个:
1、两个端点所在的格子在网格的边界。
2、蛇构成一个环,即两个端点相邻(垂直或水平,不能斜着),至少要占据4个格子(否则没法形成环)。
给定一个网格,用r x c的字符矩阵描述:‘#’代表障碍物,‘.’代表空地。在满足前面所述的条件下覆盖所有空地,并使得端点在网格边界(即不构成环)的蛇尽量少。(如果一条蛇既构成环,又是端点在边界,那么不计入答案)
例如,以下网格:
可以由下面三种方案覆盖。还有其他的方案,但是没法仅用一条不构成环的蛇就覆盖整个网络的方案。
给定一个网络的描述,输出最少需要多少条不构成环的蛇来覆盖这个网格。如果不存在能够覆盖网格的方案,输出-1。
「输入格式」
一个字符矩阵,行数和列数不超过12。输入文件中没有多余的空白字符,每行之后都有换行符。
「输出格式」
输出满足题目要求的那个整数。
题解
考场上写个随机起点贪心啥的得了70+分
善良的学长的题解
本题中,如果构成环,则二分染色后,蛇的头和尾异色,以此为突破点。
首先棋盘黑白染色,之后源向白色点流入2流量,黑色点向汇流出2流量。这2流量是强制的,也即需要上下界来限制。
同时,白色点可向相邻的点流出1流量。 这样,任何一个环形蛇,均被拆成了两段,一段是源-头-尾 另一段是源-头-躯干-尾
下面考虑另一种蛇
这里,另一种蛇可以被认为,在边界上,头部花费1的代价,取消掉1的流入流量,尾部花费1的代价,取消掉1的流出流量。
所以对于白色点,建一条到汇的,容量1,费用1的边。
对于黑色点,建一条从源点出发的,容量1,费用1的边。
此时求出最小费用可行流就能得出答案。
显然,如果无法满足下界流量,那么无解,输出-1。
不靠谱的乱搞
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | #include<map> #include<set> #include<ctime> #include<cstdio> #include<cstring> #include<vector> #include<cstdlib> #include<iostream> #include<algorithm> #define inf 1000000000 #define ll long long using namespace std; unsigned ll rnd; int n=1,m,tot,ind,ans=inf; int id[305],now[305],d[305],p[25][25]; int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0}; char a[25][25]; bool mark[305],vis[305]; vector<int>e[305],q; bool cmp(int a,int b) { 	if(vis[a]!=vis[b])return vis[a]<vis[b]; 	return now[a]<now[b]; } int cal(int t) { 	int x=t,num=1;vis[t]=1; 	while(1) 	{ 		q.push_back(x); 		sort(e[x].begin(),e[x].end(),cmp); 		int p=e[x][0]; 		if(p==t&&num!=2)return 0; 		else if(vis[p]) 		{ 			if(num==1)return -1; 			if(mark[t]&&mark[x])return 1; 			return -1; 		} 		else  		{ 			for(int i=0;i<e[x].size();i++)now[e[x][i]]--; 			vis[p]=1;x=p; 			num++; 		} 	} } void solve() { 	int tmp=0; 	for(int i=1;i<=ind;i++)vis[i]=0; 	for(int i=1;i<=ind;i++)now[i]=d[i]; 	for(int i=1;i<=ind;i++)id[i]=i; 	for(int i=2;i<=ind;i++) 	{ 		swap(id[i],id[rnd%i+1]); 		rnd=rnd*23+1000000007; 	} 	tot=0; 	for(int i=1;i<=ind;i++) 	{ 		int t=id[i];if(vis[t])continue; 		q.clear();int c=cal(t); 		if(c==-1) 		{ 			for(int i=0;i<q.size();i++)vis[q[i]]=0; 			for(int i=0;i<q.size();i++) 				for(int j=0;j<e[q[i]].size();j++) 					now[e[q[i]][j]]++; 			q.clear(); 		} 		else  		{ 			tmp+=c; 			tot+=q.size(); 			if(tmp>=ans)return; 		} 	} 	if(tot==ind)ans=min(ans,tmp); } int main() { 	//freopen("snake.in","r",stdin); 	//freopen("snake.out","w",stdout); 	int tim=clock(); 	rnd=rand(); 	while(scanf("%s",a[n]+1)!=EOF)n++;n--; 	m=strlen(a[n]+1); 	for(int i=1;i<=n;i++) 		for(int j=1;j<=m;j++) 		{ 			if(a[i][j]!='#')p[i][j]=++ind; 			if(i==1||i==n||j==1||j==m)mark[p[i][j]]=1; 		} 	for(int i=1;i<=n;i++) 		for(int j=1;j<=m;j++) 			for(int k=0;k<4;k++) 				if(p[i][j]) 				{ 					int x=i+xx[k],y=j+yy[k]; 					if(!p[x][y]||x<1||y<1||x>n||y>m)continue; 					e[p[i][j]].push_back(p[x][y]); 					d[p[i][j]]++; 				} 	for(int i=1;i<=ind;i++) 		if(e[i].size()==0) 		{ 			puts("-1"); 			return 0; 		} 	while(1) 	{ 		solve(); 		if(clock()-tim>470)break; 	} 	if(ans==inf)puts("-1"); 	else printf("%d\n",ans); 	return 0; } | 
费用流
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | #include<map> #include<set> #include<ctime> #include<cstdio> #include<cstring> #include<vector> #include<cstdlib> #include<iostream> #include<algorithm> #define p(i,j) (i-1)*m+j #define inf 1000000000 #define ll long long using namespace std; int xx[4]={0,0,1,-1},yy[4]={1,-1,0,0}; int S,T,SS,TT,tot; int n=1,m,cnt=1,cost,flow; int q[305],dis[305],last[305],in[305]; bool inq[305],mark[305]; char a[15][15]; struct edge{ 	int to,next,v,c; }e[100005]; void insert(int u,int v,int w,int c) { 	e[++cnt]=(edge){v,last[u],w,c};last[u]=cnt; 	e[++cnt]=(edge){u,last[v],0,-c};last[v]=cnt; } int spfa(int x,int y) { 	int head=0,tail=1; 	memset(dis,127,sizeof(dis)); 	dis[y]=0;q[0]=y; 	while(head!=tail) 	{ 		int now=q[head];head++;inq[now]=0; 		if(head==300)head=0; 		for(int i=last[now];i;i=e[i].next) 			if(dis[e[i].to]>dis[now]-e[i].c&&e[i^1].v) 			{ 				dis[e[i].to]=dis[now]-e[i].c; 				if(!inq[e[i].to])q[tail++]=e[i].to; 				if(tail==300)tail=0; 				inq[e[i].to]=1; 			} 	} 	return dis[x]<inf; } int dfs(int x,int y,int f) { 	mark[x]=1; 	if(x==y)return f; 	int used=0,w; 	for(int i=last[x];i;i=e[i].next) 		if(!mark[e[i].to]&&dis[x]-e[i].c==dis[e[i].to]&&e[i].v) 		{ 			w=dfs(e[i].to,y,min(e[i].v,f-used)); 			e[i].v-=w;e[i^1].v+=w; 			used+=w;cost+=e[i].c*w; 			if(used==f)return f; 		} 	return used; } void build() { 	for(int i=1;i<=n;i++) 		for(int j=1;j<=m;j++) 			if(a[i][j]=='.') 			{ 				if((i+j)&1) 				{ 					if(i==1||j==1||i==n||j==m)insert(p(i,j),T,1,1); 					in[S]-=2;in[p(i,j)]+=2; 					for(int k=0;k<4;k++) 					{ 						int x=i+xx[k],y=j+yy[k]; 						if(x<1||y<1||x>n||y>m||a[x][y]=='#')continue; 						insert(p(i,j),p(x,y),1,0); 					} 				} 				else  				{ 					if(i==1||j==1||i==n||j==m)insert(S,p(i,j),1,1); 					in[p(i,j)]-=2;in[T]+=2;					 				} 			} 	for(int i=1;i<=T;i++) 	{ 		if(in[i]>0)insert(SS,i,in[i],0); 		if(in[i]<0)insert(i,TT,-in[i],0); 	} } void dinic(int x,int y) { 	while(spfa(x,y)) 	{ 		memset(mark,0,sizeof(mark)); 		mark[y]=1; 		while(mark[y]) 		{ 			mark[y]=0; 			flow+=dfs(x,y,inf); 		} 	} } bool check() { 	for(int i=last[SS];i;i=e[i].next) 		if(e[i].v)return 0; 	return 1; } int main() { 	//freopen("snake.in","r",stdin); 	//freopen("snake.out","w",stdout); 	while(scanf("%s",a[n]+1)!=EOF)n++;n--; 	m=strlen(a[n]+1); 	S=n*m+1;T=S+1;SS=T+1;TT=SS+1; 	build(); 	insert(T,S,inf,0); 	dinic(SS,TT); 	if(check())printf("%d\n",cost/2); 	else puts("-1"); 	return 0; } | 
 
			
http://blog.csdn.net/zzzzzfy
..?
黄学长讲的好,乱搞也写得好!
请问学长这题有没有可以输出一组解的方法
据说是TC上的原题,原题是要输出解的0.0我没考虑过
刚才问了出题人 他说可以通过残量网络来求出