hdu 3251(最小割+輸出割邊)
阿新 • • 發佈:2018-12-09
大致題意:
有一個國家,有許多城市,一條道路連線兩個城市,拆掉這條路的花費為w,國王居住在城市1,因為你拯救了國家,所以國王現在要獎賞你一些城市,可選的城市有f個,每個城市都有一定的價值,當你選擇一些城市之後要拆掉一些道路使得國王不能從城市1走到你所選的任一個城市,現在問你,你所能獲得的最大價值是多少。
將給出的城市和道路建圖,然後新增一個原點,將能選擇的f個城市與這個源點相連,權值為所能獲得價值。那最終獲得的價值就是f個城市之和減去拆掉的路權值之和。那麼問題轉換成,刪掉哪些邊,使得城市1,不能到達源點,儘量使得刪掉的邊權和最小。那這就是最小割問題了。
程式碼:
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> #include<queue> using namespace std; #define maxn 1050 #define maxn2 200050 #define inf 0x3f3f3f3f int head[maxn]; int tot; int cur[maxn]; int dis[maxn]; int vis[maxn]; struct Edge { int to; int f; int next; } edge[maxn2]; vector<int>ID; bool bfs(int s,int t) { memset(dis,-1,sizeof(dis)); queue<int>Q; dis[s]=0; Q.push(s); while(!Q.empty()) { int top=Q.front(); Q.pop(); for(int i=head[top]; i!=-1; i=edge[i].next) { if(dis[edge[i].to]==-1&&edge[i].f>0) { Q.push(edge[i].to); dis[edge[i].to]=dis[top]+1; } if(dis[t]>0)return true; } } return false; } void addedge(int u,int v,int flow) { edge[tot].to=v; edge[tot].f=flow; edge[tot].next=head[u]; head[u]=tot++; edge[tot].to=u; edge[tot].f=0; edge[tot].next=head[v]; head[v]=tot++; } int dfs(int u,int y,int t) { if(u==t)return y; int yy=0; for(int &i=cur[u]; i!=-1; i=edge[i].next) { if(edge[i].f>0&&dis[edge[i].to]==dis[u]+1&&(yy=dfs(edge[i].to,min(y,edge[i].f),t))) { edge[i].f-=yy; edge[i^1].f+=yy; return yy; } } return 0; } void solve(int u) { //cout<<u<<endl; vis[u]=1; for(int i=head[u]; i!=-1; i=edge[i].next) { if(edge[i].f>0&&!vis[edge[i].to])solve(edge[i].to); } } int main() { int t,cas=0; scanf("%d",&t); while(t--) { ID.clear(); int n,m,f,sum=0; scanf("%d%d%d",&n,&m,&f); memset(head,-1,sizeof(head)); tot=0; int a,b,c; for(int i=1; i<=m; i++) { scanf("%d%d%d",&a,&b,&c); addedge(a,b,c); } for(int i=1; i<=f; i++) { scanf("%d%d",&a,&b); addedge(a,n+1,b); sum+=b; } int s=1,t=n+1; int ans=0,res=0; while(bfs(s,t)) { //cout<<"+++"<<endl; memcpy(cur,head,sizeof(head)); while(res=dfs(s,inf,t)) { ans+=res; } } memset(vis,0,sizeof(vis)); solve(1); for(int i=0; i<tot; i+=2) { //cout<<edge[i].to<<" "<<edge[i^1].to<<endl; if(vis[edge[i^1].to]&&!vis[edge[i].to]) { if((i/2+1)<=m) ID.push_back(i/2+1); } } printf("Case %d: %d\n%d",++cas,sum-ans,ID.size()); for(int i=0; i<ID.size(); i++) { printf(" %d",ID[i]); } printf("\n"); } }