您的位置:首页 > 其它

HDU 4411 Arrest(Floyd+最小费用最大流)

2016-08-24 08:30 429 查看

Arrest

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Total Submission(s): 1932    Accepted Submission(s): 765


[align=left]Problem Description[/align]
There are (N+1) cities on TAT island. City 0 is where police headquarter located. The economy of other cities numbered from 1 to N ruined these years because they are all controlled by mafia. The police plan to catch all the mafia
gangs in these N cities all over the year, and they want to succeed in a single mission. They figure out that every city except city 0 lives a mafia gang, and these gangs have a simple urgent message network: if the gang in city i (i>1) is captured, it will
send an urgent message to the gang in city i-1 and the gang in city i -1 will get the message immediately.

The mission must be carried out very carefully. Once a gang received an urgent message, the mission will be claimed failed.

You are given the map of TAT island which is an undirected graph. The node on the graph represents a city, and the weighted edge represents a road between two cities(the weight means the length). Police headquarter has sent k squads to arrest all the mafia
gangs in the rest N cities. When a squad passes a city, it can choose to arrest the gang in the city or to do nothing. These squads should return to city 0 after the arrest mission.

You should ensure the mission to be successful, and then minimize the total length of these squads traveled.

 

[align=left]Input[/align]
There are multiple test cases.

Each test case begins with a line with three integers N, M and k, here M is the number of roads among N+1 cities. Then, there are M lines. Each of these lines contains three integers X, Y, Len, which represents a Len kilometer road between city X and city Y.
Those cities including city 0 are connected.

The input is ended by “0 0 0”.

Restrictions: 1 ≤ N ≤ 100, 1 ≤ M ≤ 4000, 1 ≤ k ≤ 25, 0 ≤ Len ≤ 1000

 

[align=left]Output[/align]
For each test case,output a single line with a single integer that represents the minimum total length of these squads traveled.

 

[align=left]Sample Input[/align]

3 4 2
0 1 3
0 2 4
1 3 2
2 3 2
0 0 0

 

[align=left]Sample Output[/align]

14

 

[align=left]Source[/align]
2012 ACM/ICPC Asia Regional Hangzhou Online

 

[align=left]Recommend[/align]
liuyiding   |   We have carefully selected several similar problems for you:  5867 5866 5865 5864 5863 
 
题目大意:

    有一个城市0,和N个城市1~N,给出一些城市之间的距离。城市0最多有K个警察,要按照城市从1到N的顺序抓住N个城市中每个城市的罪犯再返回城市0,求最小路程。

解题思路:

    首先,最小费用最大流求的是在一个有流量限制的网络中,保证流量最大的前提下使得花费最小的流量与花费。

    那么我们很容易就可以想到把警察个数看作流量,距离看作花费。由于不一定要使用全部警察。我们只需要在在城市0和终点之间连一个容量无限,花费为0的边即可。其它的就是很普通的拆点,流量限制,具体看代码。

AC代码:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;
#define mem(a,b) memset((a),(b),sizeof(a))
#define INF 0x01010101
#define fi first
#define se second

struct Edge
{
int to,next,cap,flow,cost;
};

const int maxn=100+3;
const int maxv=maxn*2;
int dist[maxn][maxn];
int N,M,K,V;
int head[maxv],tol;
int pre[maxv],dis[maxv];
bool vis[maxv];
Edge edge[maxv*maxv];

void init()
{
tol=0;
mem(head,-1);
}

void add_edge(int u,int v,int cap,int cost)
{
edge[tol].to=v;
edge[tol].cap=cap;
edge[tol].cost=cost;
edge[tol].flow=0;
edge[tol].next=head[u];
head[u]=tol++;
edge[tol].to=u;
edge[tol].cost=-cost;
edge[tol].flow=0;
edge[tol].next=head[v];
head[v]=tol++;
}

bool spfa(int s,int t)
{
queue<int> q;
for(int i=0;i<V;++i)
{
dis[i]=INF;
vis[i]=false;
pre[i]=-1;
}
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty())
{
int u=q.front(); q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost)
{
dis[v]=dis[u]+edge[i].cost;
pre[v]=i;
if(!vis[v])
{
vis[v]=true;
q.push(v);
}
}
}
}
if(pre[t]==-1)
return false;
else return true;
}

int minCostMaxFlow(int s,int t,int &cost)
{
int flow=0;
cost=0;
while(spfa(s,t))
{
int Min=INF;
for(int i=pre[t];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[t];i!=-1;i=pre[edge[i^1].to])
{
edge[i].flow+=Min;
edge[i^1].flow-=Min;
cost+=edge[i].cost*Min;
}
flow+=Min;
}
return flow;
}

int main()
{
while(~scanf("%d%d%d",&N,&M,&K)&&(N||M||K))
{
//0~N城市
//N+1~N*2抓强盗后的城市
//N*2+1源点
//N*2+2汇点
V=N*2+3;
init();
int s=N*2+1,t=N*2+2;
mem(dist,0x01);
for(int i=0;i<M;++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
dist[a][b]=dist[b][a]=min(dist[a][b],c);//有重边
}
for(int i=0;i<=N;++i)
dist[i][i]=0;
for(int k=0;k<=N;++k)//Floyd-Warshall算法,求任何两点之间的最短距离
for(int i=0;i<=N;++i)
for(int j=0;j<=N;++j)
dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
add_edge(s,0,K,0);//连接超级源点和城市0
add_edge(0,t,INF,0);//不一定使用全部警察
for(int i=1;i<=N;++i)
{
add_edge(i,i+N,INF-1,0);//最小流量限制为1
add_edge(i,i+N,1,-INF);
add_edge(0,i,INF,dist[0][i]);//警察可以直接从城市0过来
add_edge(i+N,t,INF,dist[i][0]);//警察回到城市0
for(int j=1;j<i;++j)//和前面的每个城市相连
add_edge(j+N,i,INF,dist[j][i]);
}
int ans;
minCostMaxFlow(s,t,ans);
printf("%d\n",ans+N*INF);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: