P6085 [JSOI2013] 吃货 JYY

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;

#define X first
#define Y second 
#define MP make_pair
typedef pair<int, int> PII;
const int N = 15, M = 2000010;
const int INF = 0x3f3f3f3f;

int n, k, m, P[N], deg[N], dis[N][N], f[1 << N], g[M];
bool vis[M];
vector<PII> G[N];

int read(){
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

void Pre_Work(){
	memset(dis, 0x3f, sizeof(dis));
	for(int i = 1; i <= n; i ++) dis[i][i] = 0;
	P[0] = 1;
	for(int i = 1; i <= n; i ++) P[i] = P[i - 1] * 3;
}

void Get_Map(){
	memset(g, 0x3f, sizeof(g)); g[2] = 0;
	queue<int> q; q.push(2);
	while(!q.empty()){
		int s = q.front(); q.pop();
		vis[s] = false;
		
		for(int u = 0; u < n; u ++) if((s / P[u]) % 3 > 0)
		for(int i = 0; i < (int) G[u].size(); i ++){
			int v = G[u][i].X;
			if((s / P[v]) % 3 == 0){
				int t = s + P[v] * 2;
				if(g[t] > g[s]){
					g[t] = g[s];
					if(!vis[t]) q.push(t), vis[t] = true;
				}
			}
		}
		
		for(int u = 0; u < n; u ++) if((s / P[u]) % 3 > 0)
			for(int v = 0; v < n; v ++) if((s / P[v]) % 3 == 0){
				int t = s + P[v];
				t += ((s / P[u]) % 3 == 1) ? P[u] : - P[u];
				if(g[t] > g[s] + dis[u][v]){
					g[t] = g[s] + dis[u][v];
					if(!vis[t]) q.push(t), vis[t] = true;
				}
			}
	}
}

void Get_Dis(){
	memset(f, 0x3f, sizeof(f));
	f[0] = 0;
	for(int s = 0; s < (1 << n); s ++)
		for(int u = 0; u < n; u ++) if(!(s >> u & 1))
			for(int v = u + 1; v < n; v ++) if(!(s >> v & 1)){
				int t = s + (1 << u) + (1 << v);
				f[t] = min(f[t], f[s] + dis[u][v]);
			}
}

int main(){
	n = read(), k = read();
	Pre_Work(); int sum = 0;
	for(int i = 1; i <= k; i ++){
		int u = read() - 1, v = read() - 1, w = read();
		G[u].push_back(MP(v, w));
		G[v].push_back(MP(u, w));
		dis[u][v] = dis[v][u] = min(dis[u][v], w);
		deg[u] ++, deg[v] ++; sum += w;
	}
	m = read();
	for(int i = 1; i <= m; i ++){
		int u = read() - 1, v = read() - 1, w = read();
		dis[u][v] = dis[v][u] = min(dis[u][v], w);
	}
	
	for(int k = 0; k < n; k ++)
		for(int i = 0; i < n; i ++) if(dis[i][k] != INF)
			for(int j = 0; j < n; j ++) if(dis[k][j] != INF)
				dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
	
	Get_Map(); Get_Dis();
	
	int ans = INF;
	for(int i = 0; i < P[n]; i ++){
		int s = i;
		bool flag = false;
		for(int u = 0; u < n; u ++)
			if(G[u].size() && !((s / P[u]) % 3)) {flag = true; break;}
		if(flag) continue;
		for(int u = 0; u < n; u ++)
			if(deg[u] & 1) s += ((i / P[u]) % 3 == 1) ? P[u] : - P[u];
		int t = 0;
		for(int u = 0; u < n; u ++)
			if((s / P[u]) % 3 == 1) t += (1 << u);
		ans = min(ans, g[i] + f[t]);
	}
	printf("%d\n", ans + sum);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值