题目链接:点我~~
题意:n个点m条边的有向图,f个可选城市,每个城市都有其价值w,国王的城市在1,要分配一些城市,分配的原则是:只能在规定的f个城市中选若干个,这f个城市每个都有一个价值,被选择的城市要与城市1隔离,所以需要花费一些费用来破坏边。问能获取到的最大利益,以及要破坏的边。
思路:求能获取的最大利益,先建立一个超级汇点,将f个可选城市与汇点连接,价值为权值,f个城市的价值总和减去跑出的最小割即为可获得的最大价值,过程肯定优先选取价值低的边来破坏。在残留网络中,从源点遍历所有能走到的点,即属于S集,其余的为T集,如果一条边连接着S集的点与T集的点,说明该边一定为割边。
#include <bits/stdc++.h> using namespace std; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PI; typedef pair< PI, int> PII; const double eps=1e-5; const double pi=acos(-1.0); const int mod=1e9+7; const int INF=0x3f3f3f3f; #define Key_value ch[ch[root][1]][0] #define lson l,mid,rt<<1 const int MAXN = 10000+100; #define rson mid+1,r,rt<<1|1 const int MAXM = 200000+100; struct Edge { int to,next,cap,flow; } edge[MAXM]; int tol; int head[MAXN]; int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN]; void init() { tol = 0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w,int rw=0) { edge[tol].to = v; edge[tol].cap = w; edge[tol].next = head[u]; edge[tol].flow = 0; head[u] = tol++; edge[tol].to = u; edge[tol].cap = rw; edge[tol].next = head[v]; edge[tol].flow = 0; head[v] = tol++; } int sap(int start,int end,int N) { memset(gap,0,sizeof(gap)); memset(dep,0,sizeof(dep)); memcpy(cur,head,sizeof(head)); int u = start; pre[u] = -1; gap[0] = N; int ans = 0; while(dep[start] < N) { if(u == end) { int Min = INF; for(int i = pre[u]; i != -1; i = pre[edge[i^1].to]) if(Min > edge[i].cap - edge[i].flow) Min = edge[i].cap - edge[i].flow; for(int i = pre[u]; i != -1; i = pre[edge[i^1].to]) { edge[i].flow += Min; edge[i^1].flow -= Min; } u = start; ans += Min; continue; } bool flag = false; int v; for(int i = cur[u]; i != -1; i = edge[i].next) { v = edge[i].to; if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) { flag = true; cur[u] = pre[v] = i; break; } } if(flag) { u = v; continue; } int Min = N; for(int i = head[u]; i != -1; i = edge[i].next) if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) { Min = dep[edge[i].to]; cur[u] = i; } gap[dep[u]]--; if(!gap[dep[u]])return ans; dep[u] = Min+1; gap[dep[u]]++; if(u != start) u = edge[pre[u]^1].to; } return ans; } int S[MAXM],T[MAXM]; bool vis[MAXM]; void dfs(int u) { vis[u]=1; for(int i=head[u]; ~i; i=edge[i].next) if(!vis[edge[i].to] &&edge[i].cap>edge[i].flow ) dfs(edge[i].to); } int main() { int n,m,f; int t,casee=1; scanf("%d",&t); while(t--) { init(); scanf("%d%d%d",&n,&m,&f); int u,v,w; for(int i=1; i<=m; ++i) { scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); S[i]=u,T[i]=v; } int res=0; for(int i=0; i<f; ++i) { scanf("%d%d",&u,&w); addedge(u,n+1,w); res+=w; } printf("Case %d: %d\n",casee++,res-sap(1,n+1,n+1)); memset(vis,0,sizeof(vis)); dfs(1); vector<int >ans; for(int i=1; i<=m; ++i) { if(vis[S[i]] && !vis[T[i]]) ans.push_back(i); } cout<<ans.size(); for(auto &i:ans) cout<<" "<<i; puts(""); } return 0; }
- 版权声明:本文基于《知识共享署名-相同方式共享 3.0 中国大陆许可协议》发布,转载请遵循本协议
- 文章链接:http://www.carlstedt.cn/archives/1218 (转载时请注明本文出处及文章链接)
发表评论
快来吐槽一下吧!