[스탠너 트리] HDOJ 3311 Dig The Wells

3948 단어 hdoj스탠나
제목: n+m개의 점, 점권을 주고 m2개의 변, 변권을 준다.각자 물을 마실 수 있는 최소한의 대가를 구하다.
문제 풀이 방향: DP 과정이 1차원 증가하면 물을 마실 수 있는지 없는지를 나타낸다. 스탠나 나무를 만들고 DP를 만든다.
#include <iostream>
#include <queue> 
#include <stack> 
#include <map> 
#include <set> 
#include <bitset> 
#include <cstdio> 
#include <algorithm> 
#include <cstring> 
#include <climits>
#include <cstdlib>
#include <cmath>
#include <time.h>
#define maxn 1009
#define maxm 10005
#define eps 1e-7
#define mod 1000000007
#define INF 0x3f3f3f3f
#define PI (acos(-1.0))
#define lowbit(x) (x&(-x))
#define mp make_pair
#define ls o<<1
#define rs o<<1 | 1
#define lson o<<1, L, mid 
#define rson o<<1 | 1, mid+1, R
#define pii pair<int, int>
#pragma comment(linker, "/STACK:16777216")
typedef long long LL;
typedef unsigned long long ULL;
//typedef int LL;
using namespace std;
LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;}
LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;}
// head

struct Edge
{
	int v, w;
	Edge *next;
}*H[maxn], *edges, E[maxm];

struct node
{
	int x, y, k;
	node() {}
	node(int x, int y, int k) : x(x), y(y), k(k) {}
};

queue<node> q;
int c[maxn];
int p[maxn];
int dp[maxn];
int d[maxn][1 << 6][2];
int in[maxn][1 << 6][2];
int n, m, m2, o;

void addedges(int u, int v, int w)
{
	edges->v = v;
	edges->w = w;
	edges->next = H[u];
	H[u] = edges++;
}

void init()
{
	edges = E;
	memset(H, 0, sizeof H);
	memset(p, 0, sizeof p);
	memset(d, INF, sizeof d);
	memset(dp, INF, sizeof dp);
}

void read()
{
	int u, v, w;
	for(int i = 1; i <= n + m; i++) scanf("%d", &c[i]);
	while(m2--) {
		scanf("%d%d%d", &u, &v, &w);
		addedges(u, v, w);
		addedges(v, u, w);
	}
	o = 1 << n;
	for(int i = 1; i <= n; i++) {
		p[i] = 1 << i - 1;
		d[i][p[i]][0] = 0;
		d[i][p[i]][1] = c[i];
	}
}

void spfa()
{
	while(!q.empty()) {
		int x = q.front().x, y = q.front().y, k = q.front().k;
		q.pop(), in[x][y][k] = false;
		for(Edge *e = H[x]; e; e = e->next) {
			int v = e->v, w = e->w;
			if(!k) {
				if(d[v][y | p[v]][0] > d[x][y][0] + w) {
					d[v][y | p[v]][0] = d[x][y][0] + w;
					if(!in[v][y | p[v]][0]) {
						in[v][y | p[v]][0] = true;
						q.push(node(v, y | p[v], 0));
					}
				}
				if(d[v][y | p[v]][1] > d[x][y][0] + w + c[v]) {
					d[v][y | p[v]][1] = d[x][y][0] + w + c[v];
					if(!in[v][y | p[v]][1]) {
						in[v][y | p[v]][1] = true;
						q.push(node(v, y | p[v], 1));
					}
				}
			}
			else {
				if(d[v][y | p[v]][1] > d[x][y][1] + w) {
					d[v][y | p[v]][1] = d[x][y][1] + w;
					if(!in[v][y | p[v]][1]) {
						in[v][y | p[v]][1] = true;
						q.push(node(v, y | p[v], 1));
					}
				}
			}
		}
	}
}

void work()
{
	for(int y = 0; y < o; y++) {
		for(int x = 1; x <= n + m; x++) {
			for(int i = (y - 1) & y; i; i = (i - 1) & y) {
				d[x][y][0] = min(d[x][y][0], d[x][y - i | p[x]][0] + d[x][i | p[x]][0]);
				d[x][y][1] = min(d[x][y][1], d[x][y - i | p[x]][1] + d[x][i | p[x]][0]);
				d[x][y][1] = min(d[x][y][1], d[x][y - i | p[x]][0] + d[x][i | p[x]][1]);
			//	d[x][y][1] = min(d[x][y][1], d[x][y - i | p[x]][1] + d[x][i | p[x]][1]);
			}
			if(d[x][y][0] < INF) q.push(node(x, y, 0)), in[x][y][0] = true;
			if(d[x][y][1] < INF) q.push(node(x, y, 1)), in[x][y][1] = true;
		}
		spfa();
	}
	for(int i = 0; i < o; i++)
		for(int j = 1; j <= n + m; j++)
			dp[i] = min(dp[i], d[j][i][1]);
	for(int i = 0; i < o; i++)
		for(int j = (i - 1) & i; j; j = (j - 1) & i)
			dp[i] = min(dp[i], dp[i - j] + dp[j]);
	printf("%d
", dp[o - 1]); } int main() { while(scanf("%d%d%d", &n, &m, &m2)!=EOF) { init(); read(); work(); } return 0; }

좋은 웹페이지 즐겨찾기