问题描述
国王会给你一些城市,你可以选择拥有它们 ! 你占领的城市不应该与首都相连。为了满足这个条件,你必须摧毁一些道路。同时,你必须为摧毁这些道路此付出代价 。也就是说,你的最终收入是你所占领城市的总价值,减去被毁道路的总成本。
注意,每条路都是单向的。e只有一个方向可用。有些城市是为国王保留的,所以即使首都无法到达,你也不能占领任何一座城市。首都永远是第一城市。
输入
第一行包含单个整数T (T <= 20),即测试用例的数量。每一种情况都以三个整数n、m、f (1 <= f < n <= 1000, 1 <= m < 100000)、城市数量、道路数量和可选城市数量开始。城市编号为1到n,以下m行每一行包含3个整数u, v, w,表示u市到v市的道路,费用w,以下f行每一行包含2个整数u和w,表示一个可用的u市,值w。
输出
对于每个测试用例,在第一行中打印用例号和最好的最终收益。在第二行中,打印e,即应该销毁的路的数量,然后是e个整数,即销毁的路的id。道路编号从1到m的顺序与它们在输入中出现的顺序相同。如果有多个解决方案,任何一个都可以。
Sample Input
2
4 4 2
1 2 2
1 3 3
3 2 4
2 4 1
2 3
4 4
4 4 2
1 2 2
1 3 3
3 2 1
2 4 1
2 3
4 4
Sample Output
Case 1: 3
1 4
Case 2: 4
2 1 3
最大权闭合子图模板(我也不知道是不是啦!反正都是最小割的意思 理解就好啦)。
s=1,t=n+1;…………………………ans=sum-最小割。
可以要的城市向 t 连接容量为 价格的边。两两连接的边 边容量为边的代价。
输出路径需要color一下。 。 注意找边的时候(i>>1)>m是应该break;
#include <queue>
#include <cstring>
#include <cstdio>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=1000+5;
const int M=100000+5;
const int INF=0x3f3f3f3f;
struct Edge{int to,len,nex;}edge[M*2+N*2];
int head[N],d[N];
bool vis[N];
int tot,s,t,n,m;
void add(int from,int to,int len)
{
edge[++tot]=(Edge){to,len,head[from]};head[from]=tot;
edge[++tot]=(Edge){from,0,head[to]};head[to]=tot;
}
queue<int>q;
bool bfs()
{
while(!q.empty())
q.pop();
m(d,0);
q.push(s);
d[s]=1;
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(!d[y]&&l)
{
d[y]=d[x]+1;
q.push(y);
if(y==t)
return 1;
}
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x==t)
return flow;
int res=flow,k;
for(int i=head[x];i&&res;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(l&&d[y]==d[x]+1)
{
k=dinic(y,min(res,l));
if(!k)
{
d[y]=0;
continue;
}
edge[i].len-=k;
edge[i^1].len+=k;
res-=k;
}
}
return flow-res;
}
void color(int x)
{
vis[x]=1;
for(int i=head[x];i;i=edge[i].nex)
{
int y=edge[i].to,l=edge[i].len;
if(l&&!vis[y])
color(y);
}
}
int main()
{
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;cas++)
{
m(head,0);
tot=1;
int n,m,k;
ll sum=0;
scanf("%d%d%d",&n,&m,&k);
s=1,t=n+1;
for(int i=1;i<=m;i++)
{
int a,b,v;
scanf("%d%d%d",&a,&b,&v);
add(a,b,v);
}
while(k--)
{
int x,v;
scanf("%d%d",&x,&v);
sum+=v;
add(x,t,v);
}
int maxflow=0;
while(bfs())
maxflow+=dinic(s,INF);
m(vis,0);
color(s);
queue<int>Q;
for(int i=2;i<=tot;i+=2)
{
if((i>>1)>m)
break; //剪枝。因为剩下边就是可用的城市向t连接的边了
int x=edge[i^1].to,y=edge[i].to;
if(vis[x]&&!vis[y])
{
Q.push(i>>1);
}
}
printf("Case %d: %d\n",cas,sum-maxflow);
printf("%d",Q.size());
while(!Q.empty())
{
printf(" %d",Q.front());
Q.pop();
}
printf("\n");
}
}