您的位置:首页 > 其它

hdu 1853 Cyclic Tour(费用流,判断满流)

2016-07-30 09:58 441 查看


Cyclic Tour

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

Total Submission(s): 2232    Accepted Submission(s): 1138


Problem Description

There are N cities in our country, and M one-way roads connecting them. Now Little Tom wants to make several cyclic tours, which satisfy that, each cycle contain at least two cities, and each city belongs to one cycle exactly. Tom wants the total length of
all the tours minimum, but he is too lazy to calculate. Can you help him?

 

Input

There are several test cases in the input. You should process to the end of file (EOF).

The first line of each test case contains two integers N (N ≤ 100) and M, indicating the number of cities and the number of roads. The M lines followed, each of them contains three numbers A, B, and C, indicating that there is a road from city A to city B,
whose length is C. (1 ≤ A,B ≤ N, A ≠ B, 1 ≤ C ≤ 1000).

 

Output

Output one number for each test case, indicating the minimum length of all the tours. If there are no such tours, output -1. 

 

Sample Input

6 9
1 2 5
2 3 5
3 1 10
3 4 12
4 1 8
4 6 11
5 4 7
5 6 9
6 5 4
6 5
1 2 1
2 3 1
3 4 1
4 5 1
5 6 1

 

Sample Output

42
-1

Hint In the first sample, there are two cycles, (1->2->3->1) and (6->5->4->6) whose length is 20 + 22 = 42.

题意:有n个城市,现在让n个城市形成1个或者多个圈,问最少的距离

如果不行输出-1

思路:形成一个或多个圈,明显的可以构造二分图出来。

然后用KM算法或者费用流即可。  注意不行的情况是非满流,判断下即可。

hdu3488是这个题目的升级版,数据量翻倍了,TLE= = 

估计还是得用KM算法

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
#define N 1010
#define M 30010
#define INF 0x3f3f3f3f
struct Node
{
int from,to,next,cap,cost;///起点,终点,同起点下一条边,残余流量,费用
} edge[M*7];
int cnt,head
;
int vis
,d
,pp
;
int sumflow;///最大流量总和
void init()
{
cnt=0;
memset(head,-1,sizeof(head));
}
void addedge(int from,int to,int cap,int cost)
{
edge[cnt].from=from;
edge[cnt].to=to;
edge[cnt].cost=cost;
edge[cnt].cap=cap;
edge[cnt].next=head[from];
head[from]=cnt++;
edge[cnt].from=to;
edge[cnt].to=from;
edge[cnt].cost=-cost;
edge[cnt].cap=0;
edge[cnt].next=head[to];
head[to]=cnt++;///存反向边
}
int spfa(int s,int t,int n)
{
queue<int>q;
memset(vis,0,sizeof(vis));
memset(pp,-1,sizeof(pp));///pp[i]表示最短路径上以i为终点的边的编号
for(int i=0; i<=n; i++)
d[i]=INF;
d[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(edge[i].cap>0&&d[v]>d[u]+edge[i].cost)
{
d[v]=d[u]+edge[i].cost;
pp[v]=i;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
if(d[t]==INF) return 0;///找不到一条到终点的路
return 1;
}
int MCMF(int s,int t,int n)
{
int mincost=0,minflow,flow=0;///最小费用,路径中最小流量,总流量
while(spfa(s,t,n))///找当前的最短路
{
minflow=INF+1;
for(int i=pp[t]; i!=-1; i=pp[edge[i].from])
minflow=min(minflow,edge[i].cap);///从路径中找最小的流量
flow+=minflow;///总流量加上最小流量
for(int i=pp[t]; i!=-1; i=pp[edge[i].from])
{
edge[i].cap-=minflow;///当前边减去最小流量
edge[i^1].cap+=minflow;///反向边加上最小流量
}
mincost+=d[t]*minflow;///最小费用等于路径和*每条路径的流量(经过多少次)
}
sumflow=flow;
return mincost;
}
int main()
{
int n,m,T;
int from,to,cost;
while(~scanf("%d %d",&n,&m))
{
init();
for(int i=0; i<m; i++)
{
scanf("%d %d %d",&from,&to,&cost);
addedge(from,to+n,1,cost);
}
int S=0,T=2*n+1;
for(int i=1; i<=n; i++)
addedge(S,i,1,0);
for(int i=n+1;i<=2*n;i++)
addedge(i,T,1,0);
int ans=MCMF(S,T,T);///流量为2保证只会走两次,如果是1到n有可能走多次
if(sumflow==n) printf("%d\n",ans);
else printf("-1\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: