lightoj1380 Teleport

思路:有n个城市,m条单向道路,开始你在k号城市,现在要你从k开始出发,访问每个城市至少一次,就最少的花费,不行的话就impossible,这样看的话就是搜索了,,,但是题目中还给出了条件的,,,如果x号城市你之前访问过了的,那么你可以从你现在所在城市不花时间的瞬移到x号城市去。这样一来就不再是简单的搜索了,而是最小树形图了。

// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
// #define DEBUG
#ifdef DEBUG
#define debug(...) printf( __VA_ARGS__ )
#else
#define debug(...)
#endif
#define CLR(x) memset(x, 0,sizeof x)
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
template<class T> inline T Get_Max(const T&a,const T&b){return a < b?b:a;}
template<class T> inline T Get_Min(const T&a,const T&b){return a < b?a:b;}
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
const double eps = 1e-10;
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 1010;
int in[maxn];
struct Edge{
	int u, v, w;
}E[maxn << 4];
int pre[maxn], cnt, id[maxn], vis[maxn];
int root;
int n, m, k;
int solve(){
	int sum = 0;
	while(true){
		memset(in, INF,sizeof in);
		memset(pre, -1,sizeof pre);
		for (int i = 0;i < cnt;++i){
			int u = E[i].u, v = E[i].v;
			if (E[i].w < in[v] && u != v){
				pre[v] = u;
				in[v] = E[i].w;
			}
		}
		for (int i = 0;i < n;++i){
			if (i == root) continue;
			if (in[i] == INF) return -1;
		}
		int Num = 0;
		memset(id, -1,sizeof id);
		memset(vis, -1,sizeof vis);
		in[root] = 0;
		for (int i = 0;i < n;++i){
			sum += in[i];
			int v = i;
			while(vis[v] != i && id[v] == -1 && v != root){
				vis[v] = i;
				v = pre[v];
			}
			if (v != root && id[v] == -1){
				for (int u = pre[v];u != v;u = pre[u]){
					id[u] = Num;
				}
				id[v] = Num++;
			}
		}
		if (Num == 0) break;
		for (int i = 0;i < n;++i)
			if (id[i] == -1) id[i] = Num++;
		for (int i = 0;i < cnt;++i){
			int v = E[i].v;
			E[i].u = id[E[i].u];
			E[i].v = id[E[i].v];
			if (E[i].u != E[i].v) E[i].w = E[i].w - in[v];
		}
		n = Num;
		root = id[root];
	}
	return sum;
}
int main()
{	// ios::sync_with_stdio(false);
	// freopen("in.txt","r",stdin);
	// freopen("out.txt","w",stdout);
	int t, icase = 0;
	scanf("%d",&t);
	while(t--){
		scanf("%d%d%d",&n,&m,&k);
		cnt = 0;
		int u, v, c;
		while(m--){
			scanf("%d%d%d",&u,&v,&c);
			E[cnt].u = u;E[cnt].v = v;E[cnt].w = c;
			cnt++;
		}
		root = k;
		int ans = solve();
		if (ans == -1) printf("Case %d: impossible\n", ++icase);
		else printf("Case %d: %d\n", ++icase, ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值