HDUOJ--4888--Redraw Beautiful Drawings【isap】網路流+判環,網路流
連結:http://acm.hdu.edu.cn/showproblem.php?pid=4888
題意:一個矩陣,限定每行行和、列和,每個格子數字不超過k,問矩陣是否存在,如存在判斷有單解還是多解。
思路:之前多校的題目,那時候還不會網路流,現在A掉了,矩陣的建圖模型,判斷網路流是否可行只要判斷最大流是否等於總行和或總列和即可,判環是看的別人的解題報告,方法是使用dfs尋找殘餘網路中是否有還存在容量的弧形成了環,如果有,說明可以通過這個環改變容量網路內部的增廣路方式,而源匯的流量是不會變的,就說明存在多解。如果沒有環,就是單一解。
建圖:源點向每個行節點連弧,容量為該行行和,每個列節點向匯點連邊,容量為每個列和,每個行節點與每個列節點之間連邊,容量為k。
細節:我用的我之前AC過題目的isap模板,但是WA了,我debug之後發現錯誤不會在建圖和判環裡,然後就和別人的isap代碼對照,發現了一個不一樣的地方,改之AC,不懂為何,不一樣的地方代碼中有注釋。我的理解nn個點,源點src的層次是0,則最大的層次應該就是nn-1,但是minm初始化為nn-1是WA,初始化為nn就AC了。理論上應該是初始化大於等於nn-1都是可以的,以後還是就初始化為nn吧避免莫名其妙的WA。
#include<cstring>#include<string>#include<fstream>#include<iostream>#include<iomanip>#include<cstdio>#include<cctype>#include<algorithm>#include<queue>#include<map>#include<set>#include<vector>#include<stack>#include<ctime>#include<cstdlib>#include<functional>#include<cmath>using namespace std;#define PI acos(-1.0)#define MAXN 50100#define eps 1e-7#define INF 0x7FFFFFFF#define LLINF 0x7FFFFFFFFFFFFFFF#define seed 131#define MOD 1000000007#define ll long long#define ull unsigned ll#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1struct node{ int u,v,w,next;}edge[500000];int head[820],dist[820],cur[820],fa[820],num[820],vis[820];int n,m,k,cnt,nn,src,sink;void add_edge(int a,int b,int c){ edge[cnt].u = a; edge[cnt].v = b; edge[cnt].w = c; edge[cnt].next = head[a]; head[a] = cnt++;}void bfs(){ int x,i,j; queue<int> q; memset(dist,-1,sizeof(dist)); memset(num,0,sizeof(num)); q.push(sink); dist[sink] = 0; num[0] = 1; while(!q.empty()){ x = q.front(); q.pop(); for(i=head[x];i!=-1;i=edge[i].next){ if(dist[edge[i].v]<0){ dist[edge[i].v] = dist[x] + 1; num[dist[edge[i].v]]++; q.push(edge[i].v); } } }}int augment(){ int x=sink,a=INF; while(x!=src){ a = min(a,edge[fa[x]].w); x = edge[fa[x]].u; } x=sink; while(x!=src){ edge[fa[x]].w -= a; edge[fa[x]^1].w += a; x = edge[fa[x]].u; } return a;}int isap(){ int i,x,ok,minm,flow=0; bfs(); for(i=0;i<=nn+5;i++) cur[i] = head[i]; x=src; while(dist[src]<nn){ if(x==sink){ flow += augment(); x = src; } ok=0; for(i=cur[x];i!=-1;i=edge[i].next){ if(edge[i].w && dist[x]==dist[edge[i].v]+1){ ok=1; fa[edge[i].v] = i; cur[x] = i; x = edge[i].v; break; } } if(!ok){ minm = nn;//minm = nn - 1 就WA for(i=head[x];i!=-1;i=edge[i].next) if(edge[i].w && dist[edge[i].v]<minm) minm=dist[edge[i].v]; if(--num[dist[x]]==0)break; num[dist[x]=minm+1]++; cur[x]=head[x]; if(x!=src) x=edge[fa[x]].u; } } return flow;}bool dfs(int u,int pre){ int i,j; if(vis[u]) return true; vis[u] = 1; for(i=head[u];i!=-1;i=edge[i].next){ if(edge[i].w>0&&edge[i].v!=pre&&dfs(edge[i].v,u)) return true; } vis[u] = 0; return false;}int row[410],col[410];int ans[420][420];int main(){ int i,j; int sumr,sumc; while(scanf("%d%d%d",&n,&m,&k)!=EOF){ memset(head,-1,sizeof(head)); sumr = sumc = 0; cnt = 0; src = 0; sink = n + m + 1; nn = sink + 1; for(i=1;i<=n;i++){ scanf("%d",&row[i]); sumr += row[i]; add_edge(src,i,row[i]); add_edge(i,src,0); for(j=1;j<=m;j++){ add_edge(i,j+n,k); add_edge(j+n,i,0); } } for(i=1,j=n+1;i<=m;j++,i++){ scanf("%d",&col[i]); sumc += col[i]; add_edge(j,sink,col[i]); add_edge(sink,j,0); } if(sumr!=sumc){ puts("Impossible"); continue; } int flag = 0; int flow = isap(); if(flow!=sumr){ puts("Impossible"); continue; } memset(vis,0,sizeof(vis)); for(i=1;i<=n;i++){ if(dfs(i,-1)){ flag = 1; break; } } if(flag){ puts("Not Unique"); continue; } puts("Unique"); memset(ans,0,sizeof(ans)); for(i=1;i<=n;i++){ for(j=head[i];j!=-1;j=edge[j].next){ int u = edge[j].v; if(u>n&&u<=n+m){ ans[i][u-n] = k - edge[j].w; } } } for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ if(j>1) printf(" "); printf("%d",ans[i][j]); } printf("\n"); } } return 0;}