您的位置:首页 > 其它

HDU 3311 Dig The Wells(spfa模板)

2017-06-03 09:04 302 查看
Dig The Wells
[b]Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 1233    Accepted Submission(s): 553
[/b]

[align=left]Problem Description[/align]
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.
 
[align=left]Input[/align]
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.
 
[align=left]Output[/align]
For each case, output the minimum result you can get in one line.
 
[align=left]Sample Input[/align]

3 1 3
1 2 3 4
1 4 2
2 4 2
3 4 4
4 1 4
5 5 5 5 1
1 5 1
2 5 1
3 5 1
4 5 1

 
[align=left]Sample Output[/align]

6
5
 
题意:PS(一开始看不懂参照了别人的博客翻译)给定N个寺庙,和M个另外的地方。然后给定点权,表示在这个点挖水井需要的代价。再给定边权,为建造无向边i,j的代价。然后求怎样弄最小的代价使得前N个点,就是寺庙都能从挖的井里得到水。

 
#include <iostream>
#include <vector>
#include <queue>
#define move(a) (1<<(a))//每一寺庙是否有连通井
using namespace std;
const int N = 1010;
const int inf = 0x3fffffff;
struct node{
int v,c;
};
int n,m,dp[1<<7]
,dis

;//因为最多就是5个寺庙
std::vector<node> mapp
;

void spfa(){//求最短路spfa的模板
int vis
={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();
vis[ts]=0;
k=mapp[ts].size();
for(int j=0;j<k;j++){
int v=mapp[ts][j].v;
if(dis[s][v]>dis[s][ts]+mapp[ts][j].c){
dis[s][v]=dis[s][ts]+mapp[ts][j].c;
if(!vis[v]){
q.push(v);
}
vis[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++){//第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]){//构成sta这种情况需要的更新
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];//更新这种sta情况下的dp数组
}
}
}
}
}
}

int main(){
cin.sync_with_stdio(false);
int t,a,b;
node e;
while(cin>>n>>m>>t){
for(int i=0;i<=n+m;i++){
mapp[i].clear();
}
for(int i=1;i<=n+m;i++){
cin>>e.c;
e.v=i;
mapp[0].push_back(e);
e.v=0;
mapp[i].push_back(e);
}
while(t--){
cin>>a>>b>>e.c;
e.v=a;
mapp[b].push_back(e);
e.v=b;
mapp[a].push_back(e);
}
spfa();
countDP();
cout<<dp[move(n+1)-1][0]<<endl;//n个1表示全部寺庙都连通了井
}
return 0;
}


2017-01-22 14:54:05
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: