HDU 4085 Steiner树模板称号

Dig The Wells

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 971    Accepted Submission(s): 416

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 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

Sample Output

6
5

题意:有n个和尚。每个和尚一个庙,有m个村庄,p条路。每条路有费用,每个地方打井也须要费用,求最少花多少钱能够使得全部和尚喝上水。

斯坦纳树比較裸的问题。

代码:

/* ***********************************************
Author :rabbit
Created Time :2014/7/17 0:59:57
File Name :13.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 100000000
#define eps 1e-8
#define pi acosi
typedef long long ll;
int head[1100],tol;
struct Edge{
	int next,to,val;
}edge[1001000];
void addedge(int u,int v,int w){
	edge[tol].to=v;
	edge[tol].next=head[u];
	edge[tol].val=w;
	head[u]=tol++;
}
int weight[1100],d[1100][1<<5],dp[1100],in[1010][1<<5];
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int n,m,p;
	 while(~scanf("%d%d%d",&n,&m,&p)){
		 memset(head,-1,sizeof(head));tol=0;
		 for(int i=0;i<n+m;i++)
			 scanf("%d",&weight[i]);
		 while(p--){
			 int u,v,w;
			 scanf("%d%d%d",&u,&v,&w);
			 u--;v--;
			 addedge(u,v,w);
			 addedge(v,u,w);
		 }
		 for(int i=0;i<n+m;i++)
			 for(int j=0;j<(1<<n);j++)
				 d[i][j]=INF;
		 for(int i=0;i<(1<<n);i++)dp[i]=INF;
		 memset(in,0,sizeof(in));
		 for(int i=0;i<n;i++)
			 d[i][1<<i]=weight[i];
		 for(int i=1;i<(1<<n);i++){
			 queue<int> Q;
			 for(int j=0;j<n+m;j++){
				 for(int k=i&(i-1);k;k=(k-1)&i)
					 d[j][i]=min(d[j][i],d[j][i-k]+d[j][k]-weight[j]);
				 if(d[j][i]<INF)Q.push(100000*j+i),in[j][i]=1;
			 }
			 while(!Q.empty()){
				 int v=Q.front()/100000,t=Q.front()%100000;
				 Q.pop();
				 in[v][t]=0;
				 for(int e=head[v];e!=-1;e=edge[e].next){
					 int s=edge[e].to;
					 if(d[s][t]>d[v][t]+edge[e].val+weight[s]-weight[v]){
						 d[s][t]=d[v][t]+edge[e].val+weight[s]-weight[v];
						 if(!in[s][t]){
							 in[s][t]=1;
							 Q.push(100000*s+t);
						 }
					 }
				 }
			 }
		 }
		 for(int i=1;i<(1<<n);i++)
			 for(int j=0;j<n+m;j++)
				 dp[i]=min(dp[i],d[j][i]);
		 for(int i=1;i<(1<<n);i++){
			 for(int j=i&(i-1);j;j=i&(j-1))
				 dp[i]=min(dp[i],dp[j]+dp[i-j]);
		 }
		 cout<<dp[(1<<n)-1]<<endl;
	 }
     return 0;
}
时间: 2024-11-09 03:38:37

HDU 4085 Steiner树模板称号的相关文章

HDU 1251 Trie树模板题

1.HDU 1251 统计难题  Trie树模板题,或者map 2.总结:用C++过了,G++就爆内存.. 题意:查找给定前缀的单词数量. #include<iostream> #include<cstring> #include<cmath> #include<queue> #include<algorithm> #include<cstdio> #define max(a,b) a>b?a:b #define F(i,a,b

HDU(1166),线段树模板,单点更新,区间总和

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 第一次做线段树,帆哥的一句话,我记下来了,其实,线段树就是一种处理数据查询和更新的手段. 然后,我的代码风格,是网上的大牛们的辛苦总结,我就套用了.这里,我还是简单说一下线段树,说的不好,主要方便自己复习. 线段树,3个步骤,建树,查询,更新, 建树:到底部就是a[]数组的值,建立左右子树后,向上推根,根为左右子树的值 更新:类似建树,二分,找到单点所在区间,更新该区间,记得上一个区间也要变化

HDU 1166 线段树模板题

坐了3天的火车,终于到外婆家了(┬_┬).这次北京之旅颇有感触,虽然学到的东西不是很多(主要是自己的原因,没有认真学,并不是老师讲的不好),不过出去见见世面也是好的.最后一场比赛印象颇深,被虐的有点惨....记得当时有道题感觉自己能过,想用数组模拟链表水过,可是无论怎么优化一直超时@[email protected]后面比完后听朋友说那题应该用线段树做,顿时恍然大悟,然并卵,线段树的模板早忘了.....今天做道线段树的模板题先复习一下,过会再想想那道题. 敌兵布阵 Time Limit: 200

hdu 2665 划分树模板题(可作为模板)

Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 6951    Accepted Submission(s): 2214 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The fi

hdu 1251 字典树模板题 ---多串 查找单词出现次数

这道题题目里没有给定数据范围 我开了2005  疯狂的WA 然后开了50000, A掉  我以为自己模板理解错  然后一天没吃饭,饿得胃疼还是想着把这题A掉再去吃,谁知竟然是这样的问题,,,呵呵~~~ 只是记录下这道题学到的方法吧: for(rt = 0; *s; rt = nxt, ++s) { nxt=tree[rt][*s-tb]; if(!nxt) { nxt=tree[rt][*s-tb]=top; memset(tree[top],0,sizeof(tree[top])); top+

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

hdu 4819 二维线段树模板

/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1010; int N, Q; struct Nodey { int l, r; int Max, Min; }; int locx[MAXN], l

hdu 4828 Xor Sum (trie 树模板题,经典应用)

hdu 4825 题目链接 题意:给定n个数,然后给出m个询问,每组询问一个数x,问n中的数y使得x和y的异或和最大. 思路:字典树..把每个数转化成二进制,注意补全前导0,使得所有数都有相同的位数. 如果想要异或和最大,那么每一位尽可能都是1. 所以做法是,先构建字典树,然后每次find的时候,尽可能按照和当前寻找的数的位相反的位的方向走(如果有的话) 比如当前位是1,那我就往0的方向走. 需要注意的是,多组数据,每次要重新初始化一遍. 做法是 在struct 中重新 root = new N

【HDU 4819】Mosaic 二维线段树模板

二维线段树的模板题,和一维一样的思路,更新的时候注意一下细节. 存模板: /* 二维线段树模板整理 */ #include<cstdio> #include<algorithm> using namespace std; #define lson (pos<<1) #define rson (pos<<1|1) const int maxn = 805; const int INF = (1 << 30); int n; int posX[max