题解 P2055 【[ZJOI2009]假期的宿舍】

t162

2019-08-14 14:56:46

Solution

解题思路在代码中。 ```cpp /* * 我的思路:遇到需要住宿的人就让他和源点之间连一条容量是1的边; * 如果是在校学生就把他的床和汇点之间连一条容量是1的边; * 把每个不回家的在校学生和自己的床之间连一条容量是1的边; * 把每个人和自己认识的人的床(如果有的话)之间连一条容量是1的边; * 最后跑一遍Dinic再判断流量是否等于需要住宿的总人数即可。 */ #include<bits/stdc++.h> using namespace std; #define Standard_Type long long #define Content_Type long long #define setEmpty(q) while(!q.empty())q.pop() #define FILL(a,b) memset(a,b,sizeof a) #define INF 2147483647 #define MAXM 200001 #define Queue_Standard_Type queue<Standard_Type> /*Start : Struct declaration*/ struct __EDGE{ Standard_Type from,to,next; Content_Type w; __EDGE(){ from=0; to=0; next=0; w=0; } }; /*End : Struct declaration*/ /*Start : Variable declaration*/ __EDGE edge[MAXM]; Standard_Type edgeHead[MAXM]={-1},edgeCount=-1,flag[MAXM],S,V; Standard_Type n; vector<Standard_Type> va,vb; bool vis[100]; /*End : Variable declaration*/ /*Start : Function declaration*/ void INIT(); void Add(Standard_Type,Standard_Type,Content_Type); bool BFS(); Content_Type DFS(Standard_Type,Content_Type); Content_Type Dinic(); /*End : Function declaration*/ int main(){ scanf("%lld",&n); while(~scanf("%lld",&n)){ S=0; V=n+n+1; INIT(); int x,tot=0; for(int i=1;i<=n;i++){ scanf("%d",&x); vis[i]=x; if(!x)tot++; } for(int i=1;i<=n;i++){ scanf("%d",&x); if(vis[i]){ Add(i+n,V,1); Add(V,i+n,0); if(!x){ tot++; Add(S,i,1); Add(i,S,0); Add(i,i+n,1); Add(i+n,i,0); } }else{ Add(S,i,1); Add(i,S,0); } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&x); if(x&&vis[j]){ Add(i,j+n,1); Add(j+n,i,0); Add(j,i+n,1); Add(i+n,j,0); } } } if(Dinic()>=tot)puts("^_^"); else puts("T_T"); } return 0; } /*Start : Define*/ void INIT(){ FILL(edgeHead,-1); FILL(vis,0); } void Add(Standard_Type from,Standard_Type to,Content_Type w){ edge[++edgeCount].from=from; edge[edgeCount].to=to; edge[edgeCount].w=w; edge[edgeCount].next=edgeHead[from]; edgeHead[from]=edgeCount; } bool BFS(){ Standard_Type from,to; Queue_Standard_Type Queue; FILL(flag,-1); setEmpty(Queue); flag[S]=0; Queue.push(S); while(!Queue.empty()){ from=Queue.front(); Queue.pop(); for(Standard_Type i=edgeHead[from];i!=-1;i=edge[i].next){ to=edge[i].to; if(edge[i].w!=0&&flag[to]==-1){ Queue.push(to); flag[to]=flag[from]; flag[to]++; } } } if(flag[V]!=-1)return true; return false; } Content_Type DFS(Standard_Type from,Content_Type flow){ if(from==V)return flow; Content_Type result=flow,minW; for(Standard_Type i=edgeHead[from];i!=-1;i=edge[i].next){ if(result<=0)return flow-result; if(edge[i].w!=0&&flag[from]==flag[edge[i].to]-1){ minW=DFS(edge[i].to,min(result,edge[i].w)); edge[i^1].w+=minW; edge[i].w-=minW; result-=minW; } } return flow-result; } Content_Type Dinic(){ Content_Type result=0; while(BFS()){ result+=DFS(S,INF); } return result; } /*End : Define*/ ``` 附:样例的图 ![](https://i.loli.net/2019/08/14/RHTL9cG4pb7vaZr.png) 上图最大流是2,等于需要住宿的人数,所以答案是`^_^`。 本来按照我的建图思路,P2和B1之间还有一条单向边。但鉴于P2未和源点连接,也就没画。