HDU3488:Tour

点击打开题目链接

Tour

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 1387    Accepted Submission(s): 729


Problem Description
In the kingdom of Henryy, there are N (2 <= N <= 200) cities, with M (M <= 30000) one-way roads connecting them. You are lucky enough to have a chance to have a tour in the kingdom. The route should be designed as: The route should contain one or more loops. (A loop is a route like: A->B->……->P->A.)
Every city should be just in one route.
A loop should have at least two cities. In one route, each city should be visited just once. (The only exception is that the first and the last city should be the same and this city is visited twice.)
The total distance the N roads you have chosen should be minimized.
 

Input
An integer T in the first line indicates the number of the test cases.
In each test case, the first line contains two integers N and M, indicating the number of the cities and the one-way roads. Then M lines followed, each line has three integers U, V and W (0 < W <= 10000), indicating that there is a road from U to V, with the distance of W.
It is guaranteed that at least one valid arrangement of the tour is existed.
A blank line is followed after each test case.
 

Output
For each test case, output a line with exactly one integer, which is the minimum total distance.
 

Sample Input
      
      
1 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
 

Sample Output
      
      
42
 

Source
 

Recommend
zhouzeyong
 


=====================================题目大意=====================================


设计路线来游历有着N个城市,M条单向道路的Henryy王国,路线需满足以下几点:

1、每条路线都必须包含至少一个环。

2、每个城市都只能在一条路线上。

3、一个环至少包含两个城市,一条路线上每个城市都只能经过一次。

4、所有路线所包含的N条道路的长度和必须最小。


=====================================算法分析=====================================


根据题意前三点可知,在旅游路线中,每个城市都会作为道路的起点和终点各一次且恰好各一次。

那么只需要令X集合 = 城市集合(代表起点),Y集合 = 城市集合(代表终点),城市A至城市B的单向路 = X中A至Y中B的边

(读入时注意处理重边)

则任意一种满足前三点题意的旅游路线都是X与Y的一个最大匹配。

考虑到题意第四点,那么本题即求二分图最佳完美匹配,只不过这里的完美指的是权和最小而已。


=======================================代码=======================================



#include<stdio.h>
#include<string.h>

#define MIN(A,B)  ((A)<(B)?(A):(B))
#define MAX(A,B)  ((A)>(B)?(A):(B))

const int INF1=0x7f;
const int INF4=0x7f7f7f7f;
const int MAXN=305;

int T,N,M,Edge[MAXN][MAXN],Linker[MAXN];

int TopX[MAXN],TopY[MAXN],Slack[MAXN];

bool VisX[MAXN],VisY[MAXN];

bool DFS(int X)
{
	VisX[X]=true;
	for(int y=1;y<=N;++y) if(!VisY[y])
	{
		//最大权:(TopX[X]+TopY[y])-Edge[X][y] 
		//最小权:Edge[X][y]-(TopX[X]+TopY[y])
		int slacklen=Edge[X][y]-(TopX[X]+TopY[y]);     
		if(slacklen)
		{
			Slack[y]=MIN(Slack[y],slacklen);
		}
		else
		{
			VisY[y]=true;
			if(Linker[y]==-1||DFS(Linker[y]))
			{
				Linker[y]=X;  
				return true;
			}
		}
	}
	return false;
}

void UpdateTop()
{
	int addconst=INF4;
	for(int y=1;y<=N;++y)
	{ 
		if(!VisY[y]) { addconst=MIN(addconst,Slack[y]); }
	}
	for(int i=1;i<=N;++i)
	{
		//最大权:-=
		//最小权:+=
		if(VisX[i])  { TopX[i]+=addconst; }    
		//最大权:+=
		//最小权:-=
		if(VisY[i])  { TopY[i]-=addconst; }    
		if(!VisY[i]) { Slack[i]-=addconst; } 
	}
}

int KM()
{
	memset(TopX,INF1,sizeof(TopX));
	memset(TopY,0,sizeof(TopY));
	memset(Linker,-1,sizeof(Linker));
	for(int x=1;x<=N;++x)
	{
		for(int y=1;y<=N;++y)
		{
		    //最大权:MAX
	     	//最小权:MIN
			TopX[x]=MIN(TopX[x],Edge[x][y]);   
		}
	}
	for( x=1;x<=N;++x) while(1)
	{
		memset(VisX,0,sizeof(VisX));
		memset(VisY,0,sizeof(VisY));
		memset(Slack,INF1,sizeof(Slack));
		if(DFS(x)) { break; }
		else { UpdateTop(); }
	}
	int sum=0;
	for(int i=1;i<=N;++i)
	{
		sum+=TopX[i];
		sum+=TopY[i];
	}
	return sum;
}

int main()
{
	while(scanf("%d",&T)==1) while(T--)
	{
		scanf("%d%d",&N,&M);
		//最大权:INF1=0xef
		//最小权:INF1=0x7f 
		memset(Edge,INF1,sizeof(Edge));          
		for(int i=1;i<=M;++i)
		{
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			if(w<Edge[u][v]) { Edge[u][v]=w; }
		}
		printf("%d\n",KM());
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值