题目链接
分析:感觉对最小割还是不是很理解,这个题因为标签就是最小割,所以直接用最小割去想了,能做出来,如果不看标签还真不一定。
首先题目中很明显有两个集合,一个是你的城市,一个是国王的城市(不是你的城市的都是国王的城市)。而题目要求你做什么呢,就是用最小的花费让这两个集合互不连通,当然你也可以选择将你的城市中的一些城市让给国王,同样你也不再获得这个城市所带来的收益,这不免让人联想到“割”这个概念,由于你的城市可以转换成国王的城市,也就是你可以抛弃掉某个城市,但这样需要一定的花费,所以我们引入汇点T,规定与T相连的都是你的城市(假设初始时f个城市都是你的),连一条容量为结点权值的边,表示必须把这条边切断才能让这个结点转化成国王的城市,同样,如果不切掉,那么就要想办法去掉和他直接或间接相连的边。
所以我们建图时这样建,让f个城市想T连容量为结点权值的弧,对给的边连一条容量为边权的弧,最后从1到T求一个最小割,价值总和减去最小割就是答案。最后输出最小割中的边即是方案。
#include<bits/stdc++.h>
#define MAIN main
#define PII pair<int,int>
#define x first
#define y second
#define lk (k<<1)
#define rk (k<<1|1)
using namespace std;
typedef long long ll;
const double eps=1e-8;
const double pi=acos(-1.0);
const int INF=0x3f3f3f3f;
const int N=1e3+10;
struct edge
{
int u,v,cap,flow,num;
edge(int u=0,int v=0,int cap=0,int flow=0,int num=0):u(u),v(v),cap(cap),flow(flow),num(num){}
};
vector<edge>E;
vector<int>g[N];
void add(int u,int v,int cap,int num)
{
E.push_back(edge(u,v,cap,0,num));
E.push_back(edge(v,u,0,0,num));
int m=E.size();
g[u].push_back(m-2);
g[v].push_back(m-1);
}
int vis[N],d[N],cur[N],n,m;
int bfs(int s,int t)
{
queue<int>q;
memset(vis,0,sizeof(vis));
d[s]=0;vis[s]=1;q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=0;i<(int)g[u].size();i++){
edge &e=E[g[u][i]];
int v=e.v;
if(!vis[v]&&e.cap>e.flow){
vis[v]=1;
q.push(v);
d[v]=d[u]+1;
}
}
}
return vis[t];
}
int dfs(int s,int t,int a)
{
if(s==t||a==0) return a;
int flow=0,f;
for(int &i=cur[s];i<(int)g[s].size();i++){
edge &e=E[g[s][i]];
int v=e.v;
if(d[v]==d[s]+1&&(f=dfs(v,t,min(a,e.cap-e.flow)))>0){
flow+=f;
e.flow+=f;
E[g[s][i]^1].flow-=f;
a-=f;
if(a==0) break;
}
}
return flow;
}
int max_flow(int s,int t)
{
int flow=0;
while(bfs(s,t))
{
memset(cur,0,sizeof(cur));
flow+=dfs(s,t,INF);
}
return flow;
}
int cost[N];
vector<int>res;
void solve()
{
for(int i=1;i<=n;i++){
if(!vis[i]) continue;
for(int j=0;j<(int)g[i].size();j++){
edge &e=E[g[i][j]];
if(e.num&&e.cap&&!vis[e.v]&&e.cap==e.flow) res.push_back(e.num);
}
}
}
int MAIN()
{
int test,tt=0,flag=0;
scanf("%d",&test);
while(test--)
{
if(flag) printf("\n");
flag=1;
int f;
scanf("%d%d%d",&n,&m,&f);
int s=1,t=n+1;
E.clear();
res.clear();
for(int i=s;i<=t;i++) g[i].clear();
memset(cost,0,sizeof(cost));
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,i);
}
for(int i=1;i<=f;i++){
int u,w;
scanf("%d%d",&u,&w);
cost[u]=w;
}
int ans=0;
for(int i=2;i<=n;i++){
if(cost[i]) {
add(i,t,cost[i],0);
ans+=cost[i];
}
}
ans-=max_flow(s,t);
printf("Case %d: %d\n",++tt,ans);
solve();
printf("%d ",(int)res.size());
for(int i=0;i<(int)res.size();i++){
printf("%d",res[i]);
if(i!=(int)res.size()-1) printf(" ");
}
}
return 0;
}