hdu3311 - Dig The Wells (斯坦纳树 spfa + DP)

来源:互联网 发布:网络直播系统 编辑:程序博客网 时间:2024/05/02 00:56

Dig The Wells

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1037    Accepted Submission(s): 453


Problem Description
You may all know the famous story “Three monks”. Recently they find some places around their temples can been used to dig some wells. It will help them save a lot of time. But to dig the well or build the road to transport the water will cost money. They do not want to cost too much money. Now they want you to find a cheapest plan.
 

Input
There are several test cases.
Each test case will starts with three numbers n , m, and p in one line, n stands for the number of monks and m stands for the number of places that can been used, p stands for the number of roads between these places. The places the monks stay is signed from 1 to n then the other m places are signed as n + 1 to n + m. (1 <= n <= 5, 0 <= m <= 1000, 0 <=p <= 5000)
Then n + m numbers followed which stands for the value of digging a well in the ith place.
Then p lines followed. Each line will contains three numbers a, b, and c. means build a road between a and b will cost c.
 

Output
For each case, output the minimum result you can get in one line.
 

Sample Input
3 1 31 2 3 41 4 22 4 23 4 4 4 1 45 5 5 5 11 5 12 5 13 5 14 5 1
 

Sample Output
65
 

Author
dandelion
 

Source
HDOJ Monthly Contest – 2010.02.06


题意:n个寺庙,m个空地,寺庙与空地之间p条路,在寺庙和空地选择地点,挖若干口井使寺庙都能有水且造价最少 (打井,修路要费用)

解析:因每个寺庙只需找到一口井,也就是寺庙的位置到井的位置只需一条路,所以我们的最后的最优解一定得到的是一棵树,可以增加一个0点来连接所有的点,其边权就是挖井的花费,所以最终以0点做为树的根节点,这样只要是到达0点则说明井己挖好。因任意两个寺庙只有两种情况(到同一口井或不同的井),到同一口井时可能最近公共父节点到井相隔几个点。不同井则最近公共父节点一定是0点。
DP[寺庙的组成状态][子树的根节点]:最小花费。
dp[ j ][ i ]=min{ dp[ j ][ i ],dp[ k ][ i ]+dp[ l ][ i ] },其中k和l是对j的一个划分。
dp[ j ][ i ]=min{ dp[ j ][ i ],dp[ j ][ i' ]+w[ i' ][ i ]},其中i和i'之间有边相连。

#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <vector>#include <queue>using namespace std;typedef  long long LL ;const LL mod=1000000009LL;const int N=10000;const int inf=0x3fffffff;int T;int n,m,k;struct edge{    int v,c;    edge(int vi,int ci)    {        v=vi,c=ci;    }};vector<edge> mp[1200];int dis[1200][1200];int dp[1<<7][1010];void spfa(){    int inq[N]= {0};    queue<int> q;    for(int i=0; i<=n+m; i++)    {        for(int t=0; t<=n+m; t++)            dis[i][t]=inf;        dis[i][i]=0;        q.push(i);        while(!q.empty())        {            int s=q.front();            q.pop();            inq[s]=0;            int sz=mp[s].size();            for(int j=0; j<sz; j++)            {                int v=mp[s][j].v;                //int c=mp[s][j].c;                if(dis[i][v] > dis[i][s] + mp[s][j].c)                {                    dis[i][v] = dis[i][s] + mp[s][j].c;                    if(!inq[v])                    {                        q.push(v);                        inq[v]=1;                    }                }            }        }    }}void DP(){    for(int sta=1; sta<(1<<(n+1)); sta++)        for(int i=0; i<=n+m; i++)            dp[sta][i]=inf;    for(int i=0; i<=n; i++)        for(int j=0; j<=n+m; j++)            dp[1<<i][j] = dis[i][j];    for(int sta=1; sta<(1<<(n+1)); sta++)    {        if(sta&(sta-1))        {            for(int i=0; i<=n+m; i++)                for(int s=sta; s>0; s=(s-1)&sta)                {                    if(dp[sta][i] > dp[sta^s][i] + dp[s][i])                    {                        dp[sta][i] = dp[sta^s][i] + dp[s][i];                    }                }            for(int i=0;i<=n+m;i++)              for(int j=0;j<=n+m;j++)              {                  if(dp[sta][i] > dp[sta][j] + dis[j][i])                    dp[sta][i]=dp[sta][j] + dis[j][i];              }        }    }}int a,b,c;int main(){    while(scanf("%d%d%d",&n,&m,&k)!=EOF)    {        for(int i=0;i<=n+m;i++) mp[i].clear();        for(int i=1; i<=n+m; i++)        {            scanf("%d",&a);            mp[0].push_back(edge(i,a));            mp[i].push_back(edge(0,a));        }        for(int i=0; i<k; i++)        {            scanf("%d%d%d",&a,&b,&c);            mp[a].push_back(edge(b,c));            mp[b].push_back(edge(a,c));        }        spfa();        DP();        printf("%d\n",dp[(1<<(n+1))-1][0]);    }    return 0;}



0 0
原创粉丝点击