[BZOJ3698]XWW的难题(有源汇上下界最大流+讲解)
題目:
我是超鏈接
題解:
建圖的話和有源匯可行流一樣
求解方法:
在新圖上跑ss到tt的最大流(附加源匯)
若新圖滿流,那么一定存在一種可行流
記此時∑f(s,i)=sum1
將t->s這條邊拆掉,在新圖上跑s到t的最大流(原源匯)
記此時∑f(s,i)=sum2
最終答案即為sum1+sum2
證明大概是這樣的:
添加附加源匯的作用:為了滿足流量平衡條件,在新圖中進行相應的補流或分流
只要連接附加源匯的邊滿流,新圖中s->t的任意一種可行流都是原圖的可行流
跑ss->tt的最大流了之后,相當于是使連接附加源匯的邊滿流,進而求出了一種可行流
再將t->s的邊拆掉(使s->t變成一個有源匯的網絡流圖),跑s到t的最大流,加上跑出來的最大流即為原圖中一種可行的最大流(并不是重新連邊,而是只拆掉t->s的邊,也就是再增廣一次!)
那么對于這道題目來說,有了上一道題的啟發,我們知道這種【矩陣,和,限制,最大值】可以轉化成網絡流問題,源點連行,邊為限制的和;列連匯點,邊為限制的和;行與列之間相連,限制為相應點的限制;他們都和附加源匯相連,補充流量;連t->s的INF邊(最大流應求一遍之后去掉)
這道題原圖的建圖方法是:
對于每一行i,s->i,[a(i,n),a(i,n)+1]
對于每一列j,j->t,[a(n,j),a(n,j)+1]
對于每一個點(i,j),i->j,[a(i,j),a(i,j)+1]
然后再按照有源匯有上下界對這個圖進行改造即可
代碼:
#include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #define INF 1e9 using namespace std; const int N=100005; int tot=-1,nxt[N],point[N],v[N],cur[N],remind[N],dis[N],r[105][105],l[105][105],pip[105][105],d[N];double ll[105] [105]; void addline(int x,int y,int cap) {++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remind[tot]=cap;++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remind[tot]=0; } int dfs(int now,int t,int limit) {if (now==t || !limit) return limit;int flow=0,f;for (int i=cur[now];i!=-1;i=nxt[i]){cur[now]=i;if (dis[v[i]]==dis[now]+1 && (f=dfs(v[i],t,min(limit,remind[i])))){limit-=f;flow+=f;remind[i]-=f;remind[i^1]+=f;if (!limit) break;}}return flow; } bool bfs(int s,int t) {queue<int>q;q.push(s);memset(dis,0x7f,sizeof(dis));dis[s]=0;for (int i=1;i<=t;i++) cur[i]=point[i];while (!q.empty()){int x=q.front(); q.pop();for (int i=point[x];i!=-1;i=nxt[i])if (dis[v[i]]>INF && remind[i]){q.push(v[i]); dis[v[i]]=dis[x]+1;}}return dis[t]<INF; } int main() {memset(point,-1,sizeof(point));memset(nxt,-1,sizeof(nxt));int n,s,t,ss,tt;scanf("%d",&n);s=n*2+1; t=s+1; ss=t+1; tt=ss+1;for (int i=1;i<=n;i++)for (int j=1;j<=n;j++) scanf("%lf",&ll[i][j]),r[i][j]=ceil(ll[i][j]),l[i][j]=floor(ll[i][j]);for (int i=1;i<n;i++){d[s]-=l[i][n],d[i]+=l[i][n],addline(s,i,r[i][n]-l[i][n]);d[i+n]-=l[n][i],d[t]+=l[n][i],addline(i+n,t,r[n][i]-l[n][i]);}for (int i=1;i<n;i++)for (int j=1;j<n;j++)d[i]-=l[i][j],d[j+n]+=l[i][j],addline(i,j+n,r[i][j]-l[i][j]),pip[i][j]=tot;int in=0,out=0;for (int i=1;i<=t;i++){if (d[i]>0) addline(ss,i,d[i]),in+=d[i];if (d[i]<0) addline(i,tt,-d[i]),out-=d[i];}addline(t,s,INF);int lj=tot;if (in!=out) {printf("No");return 0;}int maxflow=0,ans=0;while (bfs(ss,tt)) maxflow+=dfs(ss,tt,INF);if (maxflow!=in) {printf("No");return 0;}remind[lj]=remind[lj^1]=0;while (bfs(s,t)) maxflow+=dfs(s,t,INF);for (int i=1;i<n;i++)for (int j=1;j<n;j++)ans+=remind[pip[i][j]]+l[i][j];printf("%d",ans*3); }總結
以上是生活随笔為你收集整理的[BZOJ3698]XWW的难题(有源汇上下界最大流+讲解)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谷歌浏览器查看token
- 下一篇: 局域网内的ARP断网攻击