ZOJ 3613 斯坦纳树 YM 好题

5 篇文章 0 订阅
1 篇文章 0 订阅



很好的题。。

很推荐。。感谢博文http://endlesscount.blog.163.com/blog/static/821197872012525113427573/


#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <queue>
#include <iostream>

#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define repn(i,j,k) for(int i = j; i <= k;i++)

using namespace std;

const int N = 250;
int S[N],P[N];
int rs,fx[N];
int fac[N],in[N][1<<10];
int dp[N][1<<10],d[1<<10];
int n,m;
queue<pii > Q;
vector<pii >G[N];
void up(int &x,int y){
	if(x == -1) x = y;
	else x = min(x,y);
}
void spfa(){
	while(!Q.empty()){
		int u = Q.front().first , sta = Q.front().second; Q.pop();
		for(int i = 0;i < G[u].size();i++){
			int v = G[u][i].first, w =G[u][i].second;
			if(dp[v][sta|fx[v]]==-1 || dp[v][sta|fx[v]] > dp[u][sta]+w){
				dp[v][sta|fx[v]] = dp[u][sta] + w;
				if(!in[v][sta|fx[v]] && sta == (sta|fx[v])){
					in[v][sta|fx[v]] = 0;
					Q.push(mp(v,sta|fx[v]));
				}
			}
		}
		in[u][sta] = 0;
	}
}
bool check(int sta){
	int ret = 0;
	for(int i = 0;i<rs;i++)
		if(sta & (1<<i))
			ret += fac[i];
	return ret>=0;
}
int ccnt(int sta){
	int ret = 0;
	for(int i = 0;i < rs;i++)
		if(sta & (1<<i) && fac[i] < 0)
			ret++;
	return ret;
}
int main(){
	int t;
	int u,v,w;
	while(scanf("%d",&n)!=EOF){
		rs = 0;
		memset(dp,-1,sizeof(dp));
		memset(d,-1,sizeof(d));
		memset(fx,0,sizeof(fx));
		memset(in,0,sizeof(in));
		int gg = 0;
		repn(i,1,n){
			scanf("%d %d",P+i,S+i);
			if(P[i] && S[i]) P[i]--,S[i]--,gg++;
			if(P[i] || S[i]){
				fac[rs] = P[i] - S[i];
				fx[i] = 1<<rs;
				dp[i][1<<rs] = 0;
				rs++;
			}
		}
		repn(i,0,n)
			G[i].clear();
		scanf("%d",&m);
		repn(i,1,m){
			scanf("%d %d %d",&u,&v,&w);
			G[u].push_back(mp(v,w));
			G[v].push_back(mp(u,w));
		}
		int maxSta = (1 << rs)-1;
		while(!Q.empty()) Q.pop();
		repn(sta,0,maxSta){
			repn(j,1,n){
				if(fx[j] && !(fx[j]&sta)) continue;
				for(int i = (sta-1)&sta; i; i=(i-1)&sta){
					if(dp[j][i|fx[j]]!=-1 && dp[j][(sta-i)|fx[j]]!=-1){
						up(dp[j][sta] , dp[j][i|fx[j]]+dp[j][(sta-i)|fx[j]]);
					}
				}
				if(dp[j][sta]!=-1){
					// printf("fuck \n");
					Q.push(mp(j,sta)),in[j][sta] = 1;
				}
			}
			spfa();
		}
		repn(i,0,maxSta){
			repn(j,1,n){
				if(dp[j][i]!=-1)
					up(d[i],dp[j][i]);
			}
			// printf("d[%d]=%d\n",i,d[i]);
		}
		//森林
		int tmp;
		int bef = 0, ans = 0;
		repn(sta,0,maxSta){
			if(check(sta)){
				for(int j = sta&(sta-1); j ; j = (j-1)&sta){
					if(check(j) && check(sta-j) && d[j]!=-1 && d[sta-j]!=-1)
						up(d[sta],d[j]+d[sta-j]);
				}
				if(d[sta]!=-1 && ((tmp = ccnt(sta)) > bef || (tmp == bef && d[sta] < ans))){
					bef = tmp , ans = d[sta];
				}
			}
		}
		printf("%d %d\n",bef+gg,ans);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值