日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

计蒜客 91 地铁 HDU 5263 平衡大师(二分+网络流)

發布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 计蒜客 91 地铁 HDU 5263 平衡大师(二分+网络流) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

先說PPT的思路

PPT的思路源于這句話:
對每條邊 (u, v),連一條 (u, v) 容量為 1,費用為 1 的邊。如果
流了表示刪去這條邊。

流過原圖上的邊表示刪去這條邊意味著什么呢?
令dif[u]=u的出度-入度

如圖,灰邊表示原圖上的邊,初始狀態沒有流過任何邊
因為原圖沒有邊被刪,所以dif[u]=-1

這時,如果有一流量為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]值的變化量,轉化成了流過(s,u)邊或(u,t)邊的流量

如此,限制入度與出度的差的絕對值的最大值就變得簡單了
因此考慮二分答案

設v=入度與出度的差的絕對值的最大值,二分v,然后求最少需要刪去多少的邊,判斷是否可行即可
在建圖時,

1.若dif[u]>=v:則dif[u]要減去一個數x(x>=0,因為-v<=dif[u]-x<=v,所以dif[u]-v<=x<=dif[u]+v,從s到u連一條上界為dif[u]+v,下界為dif[u]-v,費用為0的邊 2.-v<dif[u]<v:從s到u連一條上界為dif[u]+v,費用為0的邊從u到t連一條上界為v-dif[u],費用為0的邊 3.若dif[u]<=-v:從u到t連一條上界為v-dif[u],下界為-v-dif[u],費用為0的邊

跑有源匯有上下界的最小費用最大流即可

#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; }

接下來是我自己的思考產物,還未驗證

考慮如何轉化 入度與出度之差
設原圖每條邊流量為1,入度與出度之差轉化為一個點的流入量與流出量之差
此時圖是不滿足流量平衡的,所以對每個點,我們給少的流一個來處,多的流一個去處,
入度與出度之差就轉化為從來處到節點的流(或從節點到去處的流的大小

順著想下去,原圖上的邊有流流過,就代表選擇了這條邊,沒有流流過,就代表邊被刪除

考慮如何求解

原題:最多k條邊限制入度與出度之差的絕對值的最大值最小求最值
考慮二分答案入度與出度之差的絕對值變為限制(用限制流量實現),那么刪去邊數自然轉為求的最值(用費用求),與d比較判斷即可

update:
我的思路會產生一個問題,從源點到各節點的流的大小 代表 出度-入度, 從各節點到匯點的流的大小 代表 入度-出度,根據每個節點是出度大還是入度大,我們選擇連(s,u)還是(u,t)(顯然一個節點不能同時連兩種邊),但因為題目限制的是 出度與入度之差的絕對值,無論連哪種邊,其下界都會是負數,目前我想到的唯一解決方法是將所有邊的邊界整體加上n

總結

以上是生活随笔為你收集整理的计蒜客 91 地铁 HDU 5263 平衡大师(二分+网络流)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。