HDU 4085 斯坦纳树

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4085

因为这题专门花一晚上学习斯坦纳树,找到比较好的学习资料,链接在这里:http://endlesscount.blog.163.com/blog/static/821197872012525113427573/

花了很长时间照着别人写了一份自己风格的代码,慢慢理解:

/* ***********************************************
Author :rabbit
Created Time :2014/7/16 20:45:31
File Name :1.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 acos(-1.0)
typedef long long ll;
const int maxn=60;
struct Edge{
	int next,to,val;
}edge[2100];
int head[maxn],tol,n,m,K;
int s[maxn],in[maxn][1<<10],d[maxn][1<<10],dp[1<<10];
void addedge(int u,int v,int c){
	edge[tol].to=v;
	edge[tol].next=head[u];
	edge[tol].val=c;
	head[u]=tol++;
}
bool check(int x){
	int r=0;
	for(int i=0;x;i++,x>>=1)
		r+=(x&1)*(i<K?1:-1);
	return r==0;
}
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int T;
	 cin>>T;
	 while(T--){
		 memset(head,-1,sizeof(head));tol=0;
		 memset(in,0,sizeof(in));
		 memset(s,0,sizeof(s));
		 scanf("%d%d%d",&n,&m,&K);
		 int nn=1<<(2*K);
		 for(int i=1;i<=n;i++)
			 for(int j=0;j<nn;j++)
				 d[i][j]=INF;
		 while(m--){
			 int u,v,w;
			 scanf("%d%d%d",&u,&v,&w);
			 addedge(u,v,w);
			 addedge(v,u,w);
		 }
		 for(int i=1;i<=K;i++){
			 s[i]=1<<(i-1),d[i][s[i]]=0;
			 s[n-i+1]=1<<(K+i-1),d[n-i+1][s[n-i+1]]=0;
		 }
		 for(int y=0;y<nn;y++){
			 queue<int> Q;
			 for(int x=1;x<=n;x++){
				 for(int i=(y-1)&y;i;i=(i-1)&y)
					 d[x][y]=min(d[x][y],d[x][i|s[x]]+d[x][(y-i)|s[x]]);
				 if(d[x][y]<INF)Q.push(x*10000+y),in[x][y]=1;
			 }
			 while(!Q.empty()){
				 int x=Q.front()/10000,y=Q.front()%10000;
				 in[x][y]=0;
				 Q.pop();
				 for(int i=head[x];i!=-1;i=edge[i].next){
					 int v=edge[i].to;
					 if(d[v][y|s[v]]>d[x][y]+edge[i].val){
						 d[v][y|s[v]]=d[x][y]+edge[i].val;
						 if(y==(y|s[v])&&!in[v][y]){
							 in[v][y]=1;
							 Q.push(10000*v+y);
						 }
					 }
				 }
			 }
		 }
		 for(int j=0;j<nn;j++){
			 dp[j]=INF;
			 for(int i=1;i<=n;i++)
				 dp[j]=min(dp[j],d[i][j]);
		 }
		 for(int i=1;i<nn;i++)
			 if(check(i))
				 for(int j=i&(i-1);j;j=(j-1)&i)
					 if(check(j))
						 dp[i]=min(dp[i],dp[j]+dp[i-j]);
		 if(dp[nn-1]>=INF)puts("No solution");
		 else printf("%d\n",dp[nn-1]);
	 }
     return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值