您的位置:首页 > 其它

【斯坦纳树】 HDOJ 3311 Dig The Wells

2015-02-10 20:00 316 查看
题意:给出n+ m个点,点权,再给出m2条边,边权。求n个点各自能喝道水的最小代价。
解题思路:DP过程增加一维,代表能不能喝到水,做一边斯坦纳树,然后再做一边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\n", dp[o - 1]);
}

int main()
{

while(scanf("%d%d%d", &n, &m, &m2)!=EOF) {
init();
read();
work();
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: