[ZJOI2009]假期的宿舍,洛谷之提高歷練地,較複雜圖論II
阿新 • • 發佈:2019-02-05
正題
這道題根據題意我們可以發現,一部分人有床,一部分人沒有床,一部分人需要床,一部分人不需要床。然而那些人有潔癖,只會睡在自己的或者認識的人的床。
那麼很明顯我們就想到了二分圖最大匹配。把有床的人和需要床的人的集合分為左右兩個集合,那麼很明顯有床的人可以貢獻一的流量(一張床),而需要床的人需要享受一的流量(一張床),所以構圖方法就顯然了,從begin到每個有床的人建一條流量為1的邊,從每個需要床的人到end建一條流量為1的邊,然後中間認識的人建一條邊即可。這道題跟飛行員匹配問題有點像
#include<cstdio> #include<cstdlib> #include<cstring> #include<queue> using namespace std; int n; struct edge{ int y,next,c; }s[100010]; int first[1010]; int h[1010]; int t; int len=1; int begin,end; bool tf[1010]; queue<int> f; void ins(int x,int y,int c){ len++; s[len].y=y;s[len].c=c;s[len].next=first[x];first[x]=len; len++; s[len].y=x;s[len].c=0;s[len].next=first[y];first[y]=len; } bool bfs(){ f.push(begin); memset(h,-1,sizeof(h)); h[begin]=1; while(!f.empty()){ int x=f.front(); f.pop(); for(int i=first[x];i!=0;i=s[i].next){ int y=s[i].y; if(h[y]==-1 && s[i].c>0){ h[y]=h[x]+1; f.push(y); } } } return h[end]!=-1; } int dfs(int x,int t){ if(x==end) return t; int tot=0; for(int i=first[x];i!=0;i=s[i].next){ int y=s[i].y; if(tot==t) return t; if(h[y]==h[x]+1 && s[i].c>0){ int my=dfs(y,min(t-tot,s[i].c)); tot+=my;s[i].c-=my;s[i^1].c+=my; } } if(tot==0) h[x]=0; return tot; } int max_flow(){ int tot=0; while(bfs()){ int dx=dfs(begin,1e9); while(dx!=0){ tot+=dx; dx=dfs(begin,1e9); } } return tot; } int main(){ scanf("%d",&t); while(t--){ len=1; memset(first,0,sizeof(first)); scanf("%d",&n); memset(tf,false,sizeof(tf)); begin=0,end=2*n+1; int tt=0; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); if(x==1) { tf[i]=true; ins(n+i,end,1); } } for(int i=1;i<=n;i++){ int x; scanf("%d",&x); if(x==1 && tf[i]==true) tt++; else ins(begin,i,1); } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ int x; scanf("%d",&x); if(i==j || x==1) ins(i,j+n,1); } if(max_flow()==n-tt) printf("^_^\n"); else printf("T_T\n"); } }