杭电2121 Ice_cream’s world II(不定根最小树形图)

Ice_cream’s world II

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2832    Accepted Submission(s): 662


Problem Description
After awarded lands to ACMers, the queen want to choose a city be her capital. This is an important event in ice_cream world, and it also a very difficult problem, because the world have N cities and M roads, every road was directed. Wiskey is a chief engineer in ice_cream world. The queen asked Wiskey must find a suitable location to establish the capital, beautify the roads which let capital can visit each city and the project’s cost as less as better. If Wiskey can’t fulfill the queen’s require, he will be punishing.
 

Input
Every case have two integers N and M (N<=1000, M<=10000), the cities numbered 0…N-1, following M lines, each line contain three integers S, T and C, meaning from S to T have a road will cost C.
 

Output
If no location satisfy the queen’s require, you must be output “impossible”, otherwise, print the minimum cost in this project and suitable city’s number. May be exist many suitable cities, choose the minimum number city. After every case print one blank.
 

Sample Input
  
  
3 1 0 1 1 4 4 0 1 10 0 2 10 1 3 20 2 3 30
 

Sample Output
  
  
impossible 40 0
一直超时,找半天竟然是pre[u]=v;写反了,然后输出答案却正确,,。。。。加油!2014-10-23 18:47更新,加油!!!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAX 1005
#define INF INT_MAX
typedef __int64 type;
struct Edge{
	int u,v;
	type w;
}edge[MAX*MAX];
int pos;
int vis[MAX],id[MAX];
__int64 minIn[MAX];
int pre[MAX];
type Directed_MST(int root,int V,int E){
	__int64 ans=0;
	int u,v;
	while(1){
		for(int i=0;i<=V;i++)
			minIn[i]=INF;
		for(int i=0;i<E;i++){
			u=edge[i].u;v=edge[i].v;
			if(minIn[v]>edge[i].w&&u!=v){
				minIn[v]=edge[i].w;
				pre[v]=u;
				if(u==root)pos=i;	
			}
		}
		for(int i=0;i<V;i++){
			if(i==root)continue;
			if(minIn[i]==INF) return -1;
		}
		memset(vis,-1,sizeof(vis));
		memset(id,-1,sizeof(id));
		int cnt=0;	minIn[root]=0;
		for(int i=0;i<V;i++){
			ans+=minIn[i];
			v=i;
			while(vis[v]!=i&&id[v]==-1&&v!=root){
				vis[v]=i;v=pre[v];
			}
			if(id[v]==-1&&v!=root){
				for(u=pre[v];u!=v;u=pre[u])
					id[u]=cnt;
					
				id[v]=cnt++;
			}
		}
		if(cnt==0) break;
		for(int i=0;i<V;i++) if(id[i]==-1) id[i]=cnt++;//标记孤立点
		
		for(int i=0;i<E;i++){
			u=edge[i].u;v=edge[i].v;
			edge[i].u=id[u];edge[i].v=id[v]; 
			if(id[u]!=id[v]){
				edge[i].w-=minIn[v];
			}
		}
		V=cnt;root=id[root]; 
	}
	return ans;
}
int main(){
	int N,M;
	type ans;
	while(scanf("%d%d",&N,&M)!=EOF){
		type sum=0;
		int i;
		for(i=0;i<M;i++){
			scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w);
			edge[i].u++;edge[i].v++;
			sum+=edge[i].w;
		}
		sum++;
		for(i=M;i<M+N;i++){
			edge[i].u=0;edge[i].v=i-M+1;
			edge[i].w=sum;
		}
		 ans=Directed_MST(0,N+1,M+N);
		if(ans==-1||ans-sum>=sum)
			printf("impossible\n\n");
		else
			printf("%I64d %d\n\n",ans-sum,pos-M);
	}
return 0;
}


/*
不定根最小树形图其实就是多增加一个与所有节点都连通的虚拟节点,权值大于所有权值之和,利用这个节点去求最小树形图,最后减掉它的权值,注意的是,它的实际根节点那儿pos=i,不是点v
左改右改,细节错误太多最后还是看着答案改出来的
Time:2014-9-10 9:19
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAX=1005;
const int INF=0xfffff7f;//定义无穷大,7个F多加了个0,结果成负数。。。。 
typedef __int64 type;
struct Edge{
	int u,v;
	type w;
}edge[MAX*MAX];
int N,M,pos;
int pre[MAX],vis[MAX];
int id[MAX];
type minIn[MAX];
type Directed_MST(int root,int V,int E){
	type ret=0;
	while(1){
		for(int i=0;i<=V;i++)
			minIn[i]=INF;
		for(int i=0;i<E;i++){
			int u=edge[i].u;	int v=edge[i].v;
			if(minIn[v]>edge[i].w&&u!=v){
				minIn[v]=edge[i].w; pre[v]=u; 
			//}下边的这个判断必须在括号内  
			if(u==root)//上个节点是根节点,那么这个是实际根节点 
				pos=i;//这儿是边的位置 i,不是v 
			} 
		}
		for(int i=0;i<V;i++){
			if(i==root)continue;
			if(minIn[i]==INF)	return -1;
		}
		memset(vis,-1,sizeof(vis));
		memset(id,-1,sizeof(id));
		int cnt=0; minIn[root]=0;
		for(int i=0;i<V;i++){//找环 
			ret+=minIn[i];//加上最小权值 
			int v=i;
			while(vis[v]!=i&&id[i]==-1&&v!=root){
				vis[v]=i;v=pre[v];//注意这两个的顺序 
			}
			if(id[v]==-1&&v!=root){
				for(int u=pre[v];u!=v;u=pre[u]){
					id[u]=cnt;
				}
				id[v]=cnt++;
			}
		}
		if(cnt==0)break;//在标记剩余之前判断 无环
		for(int i=0;i<V;i++){
			if(id[i]==-1)	id[i]=cnt++;//标记剩余 
		}
		
		
		for(int i=0;i<E;i++){//缩点 
			int u=edge[i].u; int v=edge[i].v;
			edge[i].u=id[u];
			edge[i].v=id[v];
			if(id[u]!=id[v])
				edge[i].w-=minIn[v];//注意,不要错写成i 
		}
		V=cnt; 
		root=id[root];
	}
	return ret;
}
void solve(){
	while(scanf("%d%d",&N,&M)!=EOF){
		type sum=0;
		for(int i=0;i<M;i++){
			scanf("%d%d%I64d",&edge[i].u,&edge[i].v,&edge[i].w);
			edge[i].u++;edge[i].v++;//让其从 1 开始
			sum+=edge[i].w; 
		}
		sum++;
		for(int i=M;i<M+N;i++){
			edge[i].u=0;edge[i].v=i-M+1;
			edge[i].w=sum;
		}
		type ans=Directed_MST(0,N+1,N+M);
		if(ans==-1||ans-sum>=sum)
			//printf("%d\n",ans);
			printf("impossible\n\n");
		else
			printf("%I64d %d\n\n",ans-sum,pos-M); 
	} 
}
int main(){
	solve();
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值