http://acm.hdu.edu.cn/showproblem.php?pid=3081php
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5420 Accepted Submission(s): 1739
ios
1
4 5 2
1 1
2 3
3 2
4 2
4 4
1 4
2 3app
用並查集合並女生的關係,再用二分跑最大流,由於次數具備單調性,因此能夠二分ide
1 #include<iostream> 2 #include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<cstdio> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<set> 10 #define maxn 200005 11 #define MAXN 200005 12 #define mem(a,b) memset(a,b,sizeof(a)) 13 const int N=200005; 14 const int M=200005; 15 const int INF=0x3f3f3f3f; 16 using namespace std; 17 int n; 18 struct Edge{ 19 int v,next; 20 int cap,flow; 21 }edge[MAXN*20];//注意這裏要開的夠大。。否則WA在這裏真的想罵人。。問題是還不報RE。。 22 int cur[MAXN],pre[MAXN],gap[MAXN],path[MAXN],dep[MAXN]; 23 int cnt=0;//實際存儲總邊數 24 void isap_init() 25 { 26 cnt=0; 27 memset(pre,-1,sizeof(pre)); 28 } 29 void isap_add(int u,int v,int w)//加邊 30 { 31 edge[cnt].v=v; 32 edge[cnt].cap=w; 33 edge[cnt].flow=0; 34 edge[cnt].next=pre[u]; 35 pre[u]=cnt++; 36 } 37 void add(int u,int v,int w){ 38 isap_add(u,v,w); 39 isap_add(v,u,0); 40 } 41 bool bfs(int s,int t)//其實這個bfs能夠融合到下面的迭代裏,可是好像是時間要長 42 { 43 memset(dep,-1,sizeof(dep)); 44 memset(gap,0,sizeof(gap)); 45 gap[0]=1; 46 dep[t]=0; 47 queue<int>q; 48 while(!q.empty()) 49 q.pop(); 50 q.push(t);//從匯點開始反向建層次圖 51 while(!q.empty()) 52 { 53 int u=q.front(); 54 q.pop(); 55 for(int i=pre[u];i!=-1;i=edge[i].next) 56 { 57 int v=edge[i].v; 58 if(dep[v]==-1&&edge[i^1].cap>edge[i^1].flow)//注意是從匯點反向bfs,但應該判斷正向弧的餘量 59 { 60 dep[v]=dep[u]+1; 61 gap[dep[v]]++; 62 q.push(v); 63 //if(v==sp)//感受這兩句優化加了通常沒錯,可是有的題可能會錯,因此仍是註釋出來,到時候視狀況而定 64 //break; 65 } 66 } 67 } 68 return dep[s]!=-1; 69 } 70 int isap(int s,int t) 71 { 72 if(!bfs(s,t)) 73 return 0; 74 memcpy(cur,pre,sizeof(pre)); 75 //for(int i=1;i<=n;i++) 76 //cout<<"cur "<<cur[i]<<endl; 77 int u=s; 78 path[u]=-1; 79 int ans=0; 80 while(dep[s]<n)//迭代尋找增廣路,n爲節點數 81 { 82 if(u==t) 83 { 84 int f=INF; 85 for(int i=path[u];i!=-1;i=path[edge[i^1].v])//修改找到的增廣路 86 f=min(f,edge[i].cap-edge[i].flow); 87 for(int i=path[u];i!=-1;i=path[edge[i^1].v]) 88 { 89 edge[i].flow+=f; 90 edge[i^1].flow-=f; 91 } 92 ans+=f; 93 u=s; 94 continue; 95 } 96 bool flag=false; 97 int v; 98 for(int i=cur[u];i!=-1;i=edge[i].next) 99 { 100 v=edge[i].v; 101 if(dep[v]+1==dep[u]&&edge[i].cap-edge[i].flow) 102 { 103 cur[u]=path[v]=i;//當前弧優化 104 flag=true; 105 break; 106 } 107 } 108 if(flag) 109 { 110 u=v; 111 continue; 112 } 113 int x=n; 114 if(!(--gap[dep[u]]))return ans;//gap優化 115 for(int i=pre[u];i!=-1;i=edge[i].next) 116 { 117 if(edge[i].cap-edge[i].flow&&dep[edge[i].v]<x) 118 { 119 x=dep[edge[i].v]; 120 cur[u]=i;//常數優化 121 } 122 } 123 dep[u]=x+1; 124 gap[dep[u]]++; 125 if(u!=s)//當前點沒有增廣路則後退一個點 126 u=edge[path[u]^1].v; 127 } 128 return ans; 129 } 130 131 int m,d; 132 struct sair{ 133 int x,y; 134 }p[maxn]; 135 int Friend[205][205]; 136 int fa[maxn]; 137 138 int Find(int x){ 139 int r=x,y; 140 while(x!=fa[x]){ 141 x=fa[x]; 142 } 143 while(r!=x){ 144 y=fa[r]; 145 fa[r]=x; 146 r=y; 147 } 148 return x; 149 } 150 151 void join(int x,int y){ 152 int xx=Find(x); 153 int yy=Find(y); 154 if(xx!=yy){ 155 fa[xx]=yy; 156 } 157 } 158 int tmp; 159 int Check(int mid){ 160 isap_init(); 161 int s=0,t=n+n+1; 162 for(int i=1;i<=n;i++){ 163 for(int j=1;j<=n;j++){ 164 if(Friend[i][j]){ 165 add(i,j+n,1); 166 } 167 } 168 } 169 for(int i=1;i<=n;i++){ 170 add(s,i,mid); 171 add(n+i,t,mid); 172 } 173 n=n+n+2; 174 int tttt=isap(s,t); 175 n=tmp; 176 return tttt; 177 } 178 179 int main(){ 180 std::ios::sync_with_stdio(false); 181 int T; 182 cin>>T; 183 for(int co=1;co<=T;co++){ 184 cin>>n>>m>>d; 185 tmp=n; 186 memset(Friend,0,sizeof(Friend)); 187 for(int i=0;i<=n;i++) fa[i]=i; 188 for(int i=1;i<=m;i++) cin>>p[i].x>>p[i].y; 189 for(int i=m+1;i<=m+d;i++) cin>>p[i].x>>p[i].y; 190 for(int i=m+1;i<=m+d;i++) join(p[i].x,p[i].y); 191 for(int i=1;i<=m;i++){ 192 for(int j=1;j<=n;j++){ 193 if(Find(p[i].x)==Find(j)&&!Friend[j][p[i].y]){ 194 Friend[j][p[i].y]=1; 195 } 196 } 197 } 198 int L=0,R=n,mid; 199 while(L<=R){ 200 mid=(L+R)>>1; 201 n=tmp; 202 if(Check(mid)>=(n*mid)){ 203 L=mid+1; 204 } 205 else{ 206 R=mid-1; 207 } 208 } 209 cout<<R<<endl; 210 } 211 }