BZOJ 1443 [JSOI2009]游戏Game
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1443
分析:对于这种棋子在棋盘上走来走去,只能走相邻的格子的问题,感觉还是挺好玩的...
然后好玩归好玩,可是有点不会做啊.
貌似棋盘上相邻格子这种不断移动的问题,都大概能扯到一点网络流吧.
咦,二分图?唔...在二分图上走来走去.最后不能走的人算输?...
吖,然后结论就是:求一个最大匹配,只要放在非匹配点上就可以啦...
为什么呢?
如果放在非匹配点,那么对手只能走到匹配点上去[不然就是走到非匹配点,然后增广了,就和最大匹配不符合了...]
但是对手走到了匹配点上,我就一定能沿着匹配边往后走.
然后就是对手走一条不是匹配边的边,但是他到达的点一定有一条连出去的匹配边,不然就是找到了一条增广路,与最大匹配不符.
好神奇啊!
但是我们发现可能的最大匹配不止一种.
而且对于每一种可能的最大匹配,所有不在最大匹配中的点都可以作为最优点.
所以统计方案还有技巧.
求解方案步骤:
1.从s出发,找到所有能到达的,属于X集合的点.
能到达的这个部分包括:一是非匹配点(直接到达),二是经过一个非匹配点,然后走一条类似增广路所到达的匹配点(即可以将这条路上的匹配边和非匹配边翻转得到另一组解,而这条路的终点就是另一组解中的非匹配点)
2.从t出发,倒着找到所有能到达t的点[也就是沿着反向弧为0的边前进],属于Y集合的点
能到达t的部分包括:一是非匹配点(直接到达),二是一个匹配点,经过匹配边再到匹配边再到某个非匹配点然后到达t的过程[原理和上面的类似].
然后就比较好打了...不过似乎窝代码有点丑陋的样子= =...
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 5 using namespace std; 6 7 const int maxn=10010; 8 const int INF=0x3f3f3f3f; 9 10 struct Node{ 11 int data,next,low; 12 }node[1000010]; 13 14 #define www node[point].low 15 #define now node[point].data 16 #define then node[point].next 17 18 int n,m,cnt; 19 int s,t; 20 int que[maxn],dis[maxn]; 21 int head[maxn],cur[maxn]; 22 int tp[maxn],rx[maxn],ry[maxn]; 23 int stack[maxn],top; 24 int id[110][110],Idex; 25 int x[4]={0,0,1,-1},y[4]={1,-1,0,0}; 26 char ch[110][110]; 27 bool vis[maxn]; 28 29 struct Pot{ 30 int x,y; 31 }a[maxn]; 32 33 bool cmp(const Pot &A,const Pot &B){ 34 if(A.x!=B.x) return A.x<B.x; 35 return A.y<B.y; 36 } 37 38 inline void add(int u,int v,int w){ 39 node[cnt].data=v;node[cnt].next=head[u];node[cnt].low=w;head[u]=cnt++; 40 node[cnt].data=u;node[cnt].next=head[v];node[cnt].low=0;head[v]=cnt++; 41 } 42 43 bool BFS(){ 44 memset(dis,-1,sizeof(dis)); 45 46 int H=0,T=1,k;que[1]=s;dis[s]=0; 47 48 while(H<T){ 49 k=que[++H]; 50 for(int point=head[k];point!=-1;point=then) 51 if(www && dis[now]<0) 52 dis[now]=dis[k]+1,que[++T]=now; 53 } 54 return dis[t]>0; 55 } 56 57 int dfs(int x,int low){ 58 if(x==t) return low; 59 for(int &point=cur[x];point!=-1;point=then) 60 if(www && dis[now]==dis[x]+1){ 61 int Low=dfs(now,min(www,low)); 62 if(Low){ 63 www-=Low,node[point^1].low+=Low; 64 return Low; 65 } 66 } 67 return 0; 68 } 69 70 void Build(){ 71 int nx,ny; 72 73 for(int i=1;i<=n;i++) 74 for(int j=1;j<=m;j++) 75 if(ch[i][j]=='.'){ 76 id[i][j]=++Idex; 77 rx[Idex]=i,ry[Idex]=j; 78 } 79 s=0;t=Idex+1; 80 for(int i=s;i<=t;i++) head[i]=-1; 81 82 for(int i=1;i<=n;i++) 83 for(int j=1;j<=m;j++) 84 if(ch[i][j]=='.'){ 85 if((i^j)&1){ 86 add(s,id[i][j],1); 87 tp[id[i][j]]=1; 88 for(int k=0;k<4;k++){ 89 nx=i+x[k],ny=j+y[k]; 90 if(nx>n || nx<1 || ny<1 || ny>m || ch[nx][ny]=='#') continue; 91 add(id[i][j],id[nx][ny],1); 92 } 93 } 94 else 95 add(id[i][j],t,1),tp[id[i][j]]=2; 96 } 97 } 98 99 void Calcu(int x,int d){ 100 vis[x]=1; 101 if(tp[x]==d) stack[++top]=x; 102 for(int point=head[x];point!=-1;point=then) 103 if(!vis[now] && www==(d!=2)) Calcu(now,d); 104 } 105 106 int main(){ 107 #ifndef ONLINE_JUDGE 108 freopen("1443.in","r",stdin); 109 freopen("1443.out","w",stdout); 110 #endif 111 112 int flag,rec; 113 114 scanf("%d%d",&n,&m); 115 for(int i=1;i<=n;i++) 116 scanf("%s",ch[i]+1); 117 118 Build(); 119 rec=Idex; 120 while(BFS()){ 121 memcpy(cur,head,sizeof(head)); 122 while(flag=dfs(s,INF)) Idex-=(flag<<1); 123 } 124 125 if(!Idex){ 126 puts("LOSE"); 127 } 128 else{ 129 puts("WIN"); 130 131 Calcu(s,1); 132 memset(vis,0,sizeof(vis)); 133 Calcu(t,2); 134 135 for(int i=1;i<=top;i++){ 136 a[i].x=rx[stack[i]]; 137 a[i].y=ry[stack[i]]; 138 } 139 sort(a+1,a+top+1,cmp); 140 for(int i=1;i<=top;i++) 141 printf("%d %d\n",a[i].x,a[i].y); 142 } 143 return 0; 144 }