计蒜客 91 地铁 HDU 5263 平衡大师(二分+网络流)
先說PPT的思路
PPT的思路源于這句話:
對(duì)每條邊 (u, v),連一條 (u, v) 容量為 1,費(fèi)用為 1 的邊。如果
流了表示刪去這條邊。
流過原圖上的邊表示刪去這條邊意味著什么呢?
令dif[u]=u的出度-入度
如圖,灰邊表示原圖上的邊,初始狀態(tài)沒有流過任何邊
因?yàn)樵瓐D沒有邊被刪,所以dif[u]=-1
這時(shí),如果有一流量為1的流流過邊a,那么此流只能從u在原圖上的出邊流出,即有一流量為1的流流過了邊2,代表原圖中邊2被刪,dif[u]=dif[u]-1=-2
因此,s到u流一流量為Δx的流,dif[u]要-Δx
同理,如果有一流量為1的流流過邊b,那么此流只能從u在原圖上的入邊流入,即有一流量為1的流流過了邊1或邊3,代表原圖中邊1或邊3被刪,dif[u]=dif[u]+1=0
因此,u到t流一流量為Δx的流,dif[u]要+Δx
這樣,我們就將dif[u]值的變化量,轉(zhuǎn)化成了流過(s,u)邊或(u,t)邊的流量
如此,限制入度與出度的差的絕對(duì)值的最大值就變得簡(jiǎn)單了
因此考慮二分答案
設(shè)v=入度與出度的差的絕對(duì)值的最大值,二分v,然后求最少需要?jiǎng)h去多少的邊,判斷是否可行即可
在建圖時(shí),
跑有源匯有上下界的最小費(fèi)用最大流即可
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int N=60; const int M=100005; const int inf=0x7fffffff; struct Edge{int u,v,f,w,nxt; }edge[M<<1]; int s,t,ss,tt,S,T,head[N],cnt,inque[N],pre[N],dis[N]; queue<int> que; int Q,n,m,K,a[M],b[M],dif[N]; void add(int u,int v,int f,int w){edge[cnt].u=u;edge[cnt].v=v;edge[cnt].w=w;edge[cnt].f=f;edge[cnt].nxt=head[u];head[u]=cnt++;edge[cnt].u=v;edge[cnt].v=u;edge[cnt].w=-w;edge[cnt].f=0;edge[cnt].nxt=head[v];head[v]=cnt++; } bool spfa(){memset(dis,0x7f,sizeof(dis));memset(inque,0,sizeof(inque));memset(pre,-1,sizeof(pre));dis[S]=0;que.push(S);inque[S]=1;while(!que.empty()){int u=que.front();que.pop();inque[u]=0;for(int i=head[u];i!=-1;i=edge[i].nxt){int v=edge[i].v;if(edge[i].f>0&&dis[v]>dis[u]+edge[i].w){dis[v]=dis[u]+edge[i].w;pre[v]=i;if(!inque[v]){que.push(v);inque[v]=1;}}} }if(pre[T]==-1) return 0;return 1; } int EK(){int flow,ret=0;while(spfa()){flow=inf;int x=pre[T];while(x!=-1){flow=min(edge[x].f,flow);x=pre[edge[x].u];}x=pre[T];while(x!=-1){edge[x].f-=flow;edge[x^1].f+=flow;ret+=flow*edge[x].w;x=pre[edge[x].u];}}return ret; } bool check(int v){cnt=0;memset(head,-1,sizeof(head));s=n+1;t=n+2;ss=n+3;tt=n+4;add(t,s,inf,0);for(int i=1;i<=m;i++)add(a[i],b[i],1,1);for(int i=1;i<=n;i++){if(dif[i]>=v){add(s,i,2*v,0);add(ss,i,dif[i]-v,0);add(s,tt,dif[i]-v,0);//add(s,i,[dif[i]+v,dif[i]-v],0);//減法上下界 }else if(dif[i]>-v){add(s,i,dif[i]+v,0);//減法上界 add(i,t,v-dif[i],0);//加法上界 }else{add(i,t,2*v,0);add(ss,t,-v-dif[i],0);add(i,tt,-v-dif[i],0);//add(i,t,[v-dif[i],-v-dif[i]],0);//加法上下界 }}S=ss,T=tt;if(EK()<=K) return 1;return 0; } int main(){scanf("%d",&Q);for(int cas=1;cas<=Q;cas++){memset(dif,0,sizeof(dif));scanf("%d%d%d",&n,&m,&K);K=m-K;for(int i=1;i<=m;i++){scanf("%d%d",&a[i],&b[i]);dif[b[i]]--;dif[a[i]]++;}int l=0,r=n,mid,ans;while(l<=r){mid=(l+r)/2;if(check(mid)){ans=mid;r=mid-1;}else l=mid+1;} printf("Case %d: %d\n",cas,ans);}return 0; }接下來是我自己的思考產(chǎn)物,還未驗(yàn)證
考慮如何轉(zhuǎn)化 入度與出度之差。
設(shè)原圖每條邊流量為1,入度與出度之差轉(zhuǎn)化為一個(gè)點(diǎn)的流入量與流出量之差。
此時(shí)圖是不滿足流量平衡的,所以對(duì)每個(gè)點(diǎn),我們給少的流一個(gè)來處,多的流一個(gè)去處,
入度與出度之差就轉(zhuǎn)化為從來處到節(jié)點(diǎn)的流(或從節(jié)點(diǎn)到去處的流)的大小。
順著想下去,原圖上的邊有流流過,就代表選擇了這條邊,沒有流流過,就代表邊被刪除
考慮如何求解
原題:最多k條邊是限制,入度與出度之差的絕對(duì)值的最大值最小是求最值
考慮二分答案,入度與出度之差的絕對(duì)值變?yōu)?strong>限制(用限制流量實(shí)現(xiàn)),那么刪去邊數(shù)自然轉(zhuǎn)為求的最值(用費(fèi)用求),與d比較判斷即可
update:
我的思路會(huì)產(chǎn)生一個(gè)問題,從源點(diǎn)到各節(jié)點(diǎn)的流的大小 代表 出度-入度, 從各節(jié)點(diǎn)到匯點(diǎn)的流的大小 代表 入度-出度,根據(jù)每個(gè)節(jié)點(diǎn)是出度大還是入度大,我們選擇連(s,u)還是(u,t)(顯然一個(gè)節(jié)點(diǎn)不能同時(shí)連兩種邊),但因?yàn)轭}目限制的是 出度與入度之差的絕對(duì)值,無論連哪種邊,其下界都會(huì)是負(fù)數(shù),目前我想到的唯一解決方法是將所有邊的邊界整體加上n
總結(jié)
以上是生活随笔為你收集整理的计蒜客 91 地铁 HDU 5263 平衡大师(二分+网络流)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 消息称拼多多 Temu 第三季度销售额突
- 下一篇: 小米14系列未发先火!提前打响双十一电商