BZOJ 4006: [JLOI2015]管道连接

斯坦纳树+子集DP

spfa 9272ms

Dijkstra 13016ms

luogu Dijkstra 直接TLE

综上所述斯坦纳树直接spfa

#include<cstdio>
#include<algorithm>
using namespace std;
int Num,cnt,n,m,p,F[1005][2005],stack[1000005],instack[1005],last[1005],sta[15],cost[2005],G[2005],c[15];
struct node1{
	int c,id;
}q[15];
struct node{
	int to,next,val;
}e[6005];
void add(int a,int b,int c){
	e[++cnt].to=b;
	e[cnt].next=last[a];
	e[cnt].val=c;
	last[a]=cnt;
}
void dfs(int t,int x,int y){
	if (t>Num){
		G[x]=cost[y];
		return;
	}
	dfs(t+1,x<<1,y);
	dfs(t+1,x<<1|1,y|sta[t]);
}
int main(){
	scanf("%d%d%d",&n,&m,&p);
	for (int i=1; i<=m; i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		add(y,x,z);
	}
	for (int i=0; i<p; i++) scanf("%d%d",&q[i].c,&q[i].id);
	for (int st=1; st<=n; st++)
		for (int i=0; i<(1<<p); i++)
			F[st][i]=1e9;
	for (int i=0; i<p; i++) F[q[i].id][1<<i]=0;
	for (int i=1; i<=n; i++) F[i][0]=0;
	for (int i=0; i<(1<<p); i++){
		for (int st=1; st<=n; st++)
			for (int j=i; j; j=(j-1)&i)
				F[st][i]=min(F[st][i],F[st][j]+F[st][i^j]);
		int head=0,tail=0;
		for (int st=1; st<=n; st++) stack[++tail]=st;
		for (int st=1; st<=n; st++) instack[st]=1;
		while (head<tail){
			int x=stack[++head];
			instack[x]=0;
			for (int I=last[x]; I; I=e[I].next){
				int V=e[I].to;
				if (F[V][i]>F[x][i]+e[I].val){
					F[V][i]=F[x][i]+e[I].val;
					if (!instack[V]){
						instack[V]=1;
						stack[++tail]=V;
					}
				}
			}

		}
	}
	for (int i=0; i<(1<<p); i++) cost[i]=1e9;
	for (int i=0; i<(1<<p); i++)
		for (int st=1; st<=n; st++)
			cost[i]=min(cost[i],F[st][i]);
	for (int i=1; i<=p; i++) c[i]=q[i-1].c;
	sort(c+1,c+p+1);
	Num=unique(c+1,c+p+1)-c-1;
	for (int i=0; i<p; i++) q[i].c=lower_bound(c+1,c+Num+1,q[i].c)-c;
	for (int i=0; i<p; i++)	sta[q[i].c]|=(1<<i);
	for (int i=0; i<(1<<Num); i++) G[i]=1e9;
	dfs(1,0,0);
	for (int i=0; i<(1<<Num); i++)
		for (int j=i; j; j=(j-1)&i)
			G[i]=min(G[i],G[j]+G[i^j]);
	printf("%d\n",G[(1<<Num)-1]);
	return 0;
}

  

posted @ 2018-11-08 10:34  ~Silent  阅读(228)  评论(0编辑  收藏  举报
Live2D