HDU3311Dig The Wells(斯坦纳树,spfa+状态压缩DP)可作模板

Dig The WellsTime Limit: 6000/2000 MS (Java/Others)Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1037Accepted 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

【题目大意】

给定N个寺庙,和M个另外的地方。

然后给定点权,表示在这个点挖水井需要的代价。

再给定边权,为建造无向边i,j的代价。

然后求怎样弄最小的代价使得前N个点,就是寺庙都能从挖的井里得到水。

解析:因每个寺庙只需找到一口井,也就是寺庙的位置到井的位置只需一条路,所以我们的最后的最优解一定得到的是一棵树,可以增加一个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<stdio.h>#include<vector>#include<queue>using namespace std;#define move(a) (1<<(a))const int N = 1010;const int inf = 0x3fffffff;struct EDG{int v,c;};int n,m,dp[1<<7][N],dis[N][N];vector<EDG>map[N];void spfa()//求两点之间的最短距离{int inq[N]={0},ts,k;queue<int>q;for(int s=0;s<=n+m;s++){for(int j=0;j<=n+m;j++)dis[s][j]=inf;dis[s][s]=0;q.push(s);while(!q.empty()){ts=q.front(); q.pop();inq[ts]=0;k=map[ts].size();for(int j=0;j<k;j++){int v=map[ts][j].v;if(dis[s][v]>dis[s][ts]+map[ts][j].c){dis[s][v]=dis[s][ts]+map[ts][j].c;if(!inq[v])q.push(v),inq[v]=1;}}}}}void countDp(){for(int sta=1;sta<move(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[move(i)][j]=dis[i][j];for(int sta=1;sta<move(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 main(){int p,a,b;EDG e;while(scanf("%d%d%d",&n,&m,&p)>0){for(int i=0;i<=n+m;i++)map[i].clear();for(int i=1;i<=n+m;i++){scanf("%d",&e.c);e.v=i; map[0].push_back(e);//用挖井的花费作为i–>0边的花费,,所以最终1~n点都要归于一点0e.v=0; map[i].push_back(e);}while(p–){scanf("%d%d%d",&a,&b,&e.c);e.v=b; map[a].push_back(e);e.v=a; map[b].push_back(e);}spfa();countDp();printf("%d\n",dp[move(n+1)-1][0]);}}

你怎么样对待别人被人就怎么样对待你。

HDU3311Dig The Wells(斯坦纳树,spfa+状态压缩DP)可作模板

相关文章:

你感兴趣的文章:

标签云: