hdu3311Dig The Wells

原创 2016年08月29日 13:34:51

链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=3311

题意:n个和尚住的地方,m个其他地方。每个地方挖一口井需要花费q[i]的钱,两个地方连通需要花费对应的边权值。求所有人都能喝到水的最小花费。

分析:斯塔纳树。如hdu4085,只要在加一位二进制表示集合内是否已经有水了即可。详见代码。

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<bitset>
#include<math.h>
#include<vector>
#include<string>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=1010;
const int mod=1000000007;
const int MOD1=1000000007;
const int MOD2=1000000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const int INF=1000000010;
const ll MAX=1ll<<55;
const double eps=1e-5;
const double inf=~0u>>1;
const double pi=acos(-1.0);
typedef double db;
typedef long double ldb;
typedef unsigned int uint;
typedef unsigned long long ull;
queue<int>Q;
int n,m,p,K,T,e[N],q[N];
int dp[N][80],bo[100*N],ans[80];
int tot,u[N],v[10*N],w[10*N],pre[10*N];
inline void add(int a,int b,int c) {
    v[tot]=b;w[tot]=c;pre[tot]=u[a];u[a]=tot++;
    v[tot]=a;w[tot]=c;pre[tot]=u[b];u[b]=tot++;
}
inline void init() {
    int i,j,a,b,c;
    K=n+m;T=1<<n;
    memset(bo,0,sizeof(bo));
    tot=0;memset(u,-1,sizeof(u));
    memset(e,0,sizeof(e));
    for (i=0;i<n;i++) e[i+1]=1<<i;
    for (i=1;i<=K;i++) scanf("%d", &q[i]);
    for (i=1;i<=K;i++)
        for (j=0;j<T*2;j++) dp[i][j]=INF;
    for (i=1;i<=K;i++) dp[i][0]=dp[i][0|e[i]]=0,dp[i][T]=dp[i][T|e[i]]=q[i];
    for (i=1;i<=p;i++) {
        scanf("%d%d%d", &a, &b, &c);add(a,b,c);
    }
}
inline void spfa() {
    int i,x,y,z;
    while (!Q.empty()) {
        x=Q.front();Q.pop();bo[x]=0;
        y=x%100;x/=100;z=y/T;y%=T;
        for (i=u[x];i!=-1;i=pre[i]) {
            if (!z&&dp[v[i]][y]>dp[x][y]+w[i]) {
                dp[v[i]][y]=dp[x][y]+w[i];
                if (!bo[v[i]*100+y]) bo[v[i]*100+y]=1,Q.push(v[i]*100+y);
            }
            if (!z&&dp[v[i]][y|T]>dp[x][y]+w[i]+q[v[i]]) {
                dp[v[i]][y|T]=dp[x][y]+w[i]+q[v[i]];
                if (!bo[v[i]*100+(y|T)]) bo[v[i]*100+(y|T)]=1,Q.push(v[i]*100+(y|T));
            }
            if (z&&dp[v[i]][y|T]>dp[x][y|T]+w[i]) {
                dp[v[i]][y|T]=dp[x][y|T]+w[i];
                if (!bo[v[i]*100+(y|T)]) bo[v[i]*100+(y|T)]=1,Q.push(v[i]*100+(y|T));
            }
        }
    }
}
inline void Steiner_Tree() {
    int i,j,k;
    for (i=0;i<T;i++) {
        for (j=1;j<=K;j++)
            for (k=i;k;k=(k-1)&i) {
                dp[j][i]=min(dp[j][i],dp[j][k]+dp[j][i-k]);
                dp[j][i|T]=min(dp[j][i|T],dp[j][k|T]+dp[j][i-k]);
                dp[j][i|T]=min(dp[j][i|T],dp[j][k]+dp[j][(i-k)|T]);
            }
        for (j=1;j<=K;j++) {
            if (dp[j][i]!=INF) bo[j*100+i]=1,Q.push(j*100+i);
            if (dp[j][i|T]!=INF) bo[j*100+(i|T)]=1,Q.push(j*100+(i|T));
        }
        spfa();
    }
}
void getans() {
    for (int i=0;i<T;i++) ans[i]=INF;
    for (int i=0;i<T;i++)
        for (int j=1;j<=K;j++) ans[i]=min(ans[i],dp[j][i|T]);
    for (int i=0;i<T;i++)
        for (int j=i;j;j=(j-1)&i) ans[i]=min(ans[i],ans[j]+ans[i-j]);
    printf("%d\n", ans[T-1]);
}
int main()
{
    while (scanf("%d%d%d", &n, &m, &p)!=EOF) {
        init();
        Steiner_Tree();
        getans();
    }
    return 0;
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

HDU-3311-Dig The Wells

ACM模版描述题解斯坦纳树,模版题,状压dp,还是无法很好地理解,找了大牛们的blog,感觉好高大上……以下来自Staginner大牛的博客……这个和一般的斯坦纳树的题目不同的地方在于挖井要加点权,但...
  • f_zyj
  • f_zyj
  • 2016年11月07日 01:34
  • 346

【斯坦纳树】 HDOJ 3311 Dig The Wells

题意:给出n+ m个点,点权,再给出m2条边,边权。求n个点各自能喝道水的最小代价。 解题思路:DP过程增加一维,代表能不能喝到水,做一边斯坦纳树,然后再做一边DP。 #include #inc...

hdu 4284(状态压缩)&& poj 3311 &&,,,

题目:给出一些城市,从1出发,旅游一圈回到1,由于花费可能不够,所以选择一些城市打工,打工之前需要花费d买一个证,工资为c。选中的城市必须去工作一次,而且只能工作一次,问能不能完成旅行。 思路:先用...

hdu3311之状态压缩dp

Hie with the Pie Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 3479 ...

STNT 斯坦纳树 HDU 4085 3311

今天学习了斯坦纳树,主要是求一个最短网络。 而得到的最短网络必定是以树。 一个操作是 将两个子集 合并 一个操作是 在一个子集 加上一个点 dp[N][mark] N 代表...

HDU 5067 Harry And Dig Machine(状压DP)(TSP问题)

题目地址:HDU 5067 经典的TSP旅行商问题模型。状压DP。 先分别预处理出来每两个石子堆的距离。然后将题目转化成10个城市每个城市至少经过一次的最短时间模型。然后简单的状压DP即可。 代...

hdu5067:Harry And Dig Machine

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5067 参考思路:

hdu 5067 Harry And Dig Machine(状态压缩dp)

Harry And Dig Machine Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O...

hdu 5067 Harry And Dig Machine(BestCoder Round #14)

Harry And Dig Machine Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O...
  • caduca
  • caduca
  • 2014年10月19日 07:32
  • 711

HDU 5067-Harry And Dig Machine(DFS)

Harry And Dig Machine Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/O...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:hdu3311Dig The Wells
举报原因:
原因补充:

(最多只允许输入30个字)