您的位置:首页 > 大数据 > 人工智能

[省选前题目整理][LA 2197]Paint the Roads(费用流)

2015-03-28 11:44 381 查看

题目链接

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=11338

题目大意

给一个nn个点、mm条带权有向边的图,要你给其中的一些边涂上颜色,一条边涂颜色的代价是这条边的边权,要使得最终每个点都在kk个带颜色的环上,求最小付出代价,若无解输出−1-1。

思路

可以看成是在一个带权有向图中选若干条边,使得每个点都在kk个环上,求选的所有边的最小边权之和。观察一个点,若它在kk个环上,则它的入度和出度均等于kk。如下图是k=2k=2的情况。



那么一个很显然的思路就出来了。将每个点ii拆成两个点ii和i+ni+n。分别从SS向ii、i+ni+n向TT连容量为kk、费用为00的边(代表限制每个点的入度和出度最多等于kk),对于每条边u−>vu->v而言,从uu向v+nv+n连容量为11、费用为该边边权的边(表示选择该边可以给uu增加11个出度、给vv增加一个入度,并付出该边边权的代价)。那么如果有解的话,这个图的最大流必为n∗kn*k(每个点的入度和出度都是kk),最小费用即为答案。

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

#define MAXV 1000
#define MAXE 1000000
#define INF 0x3f3f3f3f

using namespace std;

int n,m,S,T;

struct edge
{
int u,v,w,cap,next;
}edges[MAXE];

int head[MAXV],nCount=0;

void AddEdge(int U,int V,int W,int C)
{
edges[++nCount].u=U;
edges[nCount].v=V;
edges[nCount].w=W;
edges[nCount].cap=C;
edges[nCount].next=head[U];
head[U]=nCount;
}

void add(int U,int V,int W,int C)
{
AddEdge(U,V,W,C);
AddEdge(V,U,-W,0);
}

int dist[MAXV],q[MAXE*2],pre[MAXV];
bool inQueue[MAXV];

bool SPFA()
{
memset(inQueue,false,sizeof(inQueue));
memset(pre,-1,sizeof(pre));
memset(dist,INF,sizeof(dist));
int h=0,t=1;
q[h]=S;
dist[S]=0;
inQueue[S]=true;
while(h<t)
{
int u=q[h++];
inQueue[u]=false;
for(int p=head[u];p!=-1;p=edges[p].next)
{
int v=edges[p].v;
if(dist[u]+edges[p].w<dist[v]&&edges[p].cap)
{
dist[v]=dist[u]+edges[p].w;
pre[v]=p;
if(!inQueue[v])
{
inQueue[v]=true;
q[t++]=v;
}
}
}
}
return pre[T]!=-1;
}

int MCMF(int &maxflow)
{
int cost=0;
while(SPFA())
{
int flow=INF;
for(int p=pre[T];p!=-1;p=pre[edges[p].u])
flow=min(flow,edges[p].cap);
for(int p=pre[T];p!=-1;p=pre[edges[p].u])
{
edges[p].cap-=flow;
edges[p^1].cap+=flow;
}
cost+=flow*dist[T];
maxflow+=flow;
}
return cost;
}

int main()
{
int TestCase;
scanf("%d",&TestCase);
while(TestCase--)
{
int K;
memset(head,-1,sizeof(head));
nCount=1;
S=MAXV-2,T=MAXV-1;
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
u++,v++; //!!!!输入的点是以0开始的
add(u,v+n,w,1);
}
for(int i=1;i<=n;i++)
{
add(S,i,0,K);
add(i+n,T,0,K);
}
int maxflow=0;
int cost=MCMF(maxflow);
if(maxflow!=n*K) printf("-1\n");
else printf("%d\n",cost);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: