P3264 题解

Description

LOJ 传送门

Solution

算法一

首先考虑只有一种频道的情况。

注意到最终形成的是一棵树,并且 k k k 较小,这些启发我们做状压 dp \text{dp} dp

f i , s f_{i,s} fi,s 表示,目前树的 i i i,且树内包含了情报站集合 s s s

转移的时候,我们需要分类讨论 i i i 的儿子数为 1 1 1 以及不小于 2 2 2 的情况。对于前者,转移形如 f i , s → f j , s f_{i,s} \to f_{j,s} fi,sfj,s;对于后者,转移形如 f i , t + f i , s − t → f i , s ( t ∈ s ) f_{i,t}+f_{i,s-t} \to f_{i,s}(t \in s) fi,t+fi,stfi,s(ts)

于是,我们从小到大枚举 s s s,先通过枚举子集处理第二种情况,然后通过一遍 Dijkstra 对 f 1 , s , f 2 , s , ⋯   , f n , s f_{1,s},f_{2,s},\cdots,f_{n,s} f1,s,f2,s,,fn,s 进行松弛。

时间复杂度 O ( 3 p n + m log ⁡ m 2 p ) O(3^pn+m \log m 2^p) O(3pn+mlogm2p),其中 3 p 3^p 3p 为枚举子集的复杂度。

PS: 其实这就是最小斯坦纳树的板子。

算法二

对于多个频道的情况,我们该怎么办呢?

g S g_S gS 表示,所有频道属于集合 S S S 的情报站对应的最小斯坦纳树的大小。注意到,答案即为,挑选出若干个 S S S,在它们能够覆盖到所有的情报站的前提下,让它们的 g g g 之和最小。

预处理出每个 g S g_S gS,然后进行状压 dp \text{dp} dp 即可。

时间复杂度是什么呢?似乎是 O ( 2 p ( 3 p n + m log ⁡ m 2 p ) ) O(2^p(3^pn+m \log m 2^p)) O(2p(3pn+mlogm2p)) 的,无法通过。但是,我们感觉严重跑不满,于是我们写了一个程序:

#include <bits/stdc++.h>
using namespace std;
const int maxl=15;

int n=1000,m=3000,ans;
int f[maxl],pow3[maxl],pow2[maxl];

signed main(){
    
    
	pow3[0]=pow2[0]=1;
	for (int i=1;i<=10;i++)  pow3[i]=pow3[i-1]*3,pow2[i]=pow2[i-1]*2;
	for (int i=1;i<=10;i++)  f[i]=pow3[i]*n+pow2[i]*n*10;
	for (int i=0;i<(1<<10);i++){
    
    
		int sumv=0,cnt=0;
		for (int j=1;j<=n;j++){
    
    
			if (i&(1<<(j-1)))  cnt+=j,sumv+=f[j];
		}
		ans=max(ans,sumv);
	}
	cout<<ans<<endl;
	return 0;
}

发现这个值只有 1 0 8 10^8 108 左右,所以可以通过。

Code

#include <bits/stdc++.h>
#define int long long
#pragma GCC optimize("Ofast")
#define rg register
#define inf 1000000000000007
using namespace std;
const int maxn=1005,maxm=3005,maxk=15,maxs=1030;

int read(){
    
    
	int s=0,w=1;char ch=getchar();
	while (ch<'0'||ch>'9'){
    
    if (ch=='-')  w=-w;ch=getchar();}
	while (ch>='0'&&ch<='9'){
    
    s=(s<<1)+(s<<3)+(ch^'0');ch=getchar();}
	return s*w;
}
int n,m,k,cnt,len;
int head[maxn],dis[maxn],vis[maxn],p[maxk],q[maxk],tmp[maxk];
int f[maxn][maxs],g[maxs];

struct edge{
    
    int nxt,to,dis;}e[maxm<<1];
struct node{
    
    
	int dis,pos;
	bool operator < (const node &x) const{
    
    return x.dis<dis;}
};
priority_queue<node> que;
vector<int> Bin;
void chkmin(int x,int &y){
    
    y=min(x,y);}
void add_edge(int u,int v,int w){
    
    e[++cnt].to=v,e[cnt].dis=w,e[cnt].nxt=head[u],head[u]=cnt;}

namespace Dream_Tree{
    
    
	void dijkstra(){
    
    
		while (!que.empty()){
    
    
			int now=que.top().pos;que.pop();
			if (vis[now])  continue;
			vis[now]=1;
			
			for (int i=head[now];i;i=e[i].nxt){
    
    
				int y=e[i].to;
				if (dis[y]>dis[now]+e[i].dis){
    
    
					dis[y]=dis[now]+e[i].dis;
					if (!vis[y])  que.push((node){
    
    dis[y],y});
				}
			}
		}
	}
	int solve(){
    
    
		int k=Bin.size(),fi=0;
		for (int i=1;i<=n;i++){
    
    
			for (int j=0;j<(1<<k);j++)  f[i][j]=inf;
		}
		for (int i=0;i<k;i++){
    
    
			int now=Bin[i];
			if (!fi)  fi=Bin[i];
			f[now][(1<<i)]=0;
		}
		for (int s=0;s<(1<<k);++s){
    
    
			for (rg int i=1;i<=n;++i){
    
    
				for (rg int t=(s&(s-1));t;t=(t-1)&s)
				  f[i][s]=min(f[i][s],f[i][t]+f[i][s^t]); 
			}
			for (int i=1;i<=n;i++)  vis[i]=0;
			for (rg int i=1;i<=n;i++){
    
    
				dis[i]=f[i][s];
				que.push((node){
    
    f[i][s],i});
			}
			dijkstra();
			for (int i=1;i<=n;i++)  f[i][s]=dis[i];
		}
		return f[fi][(1<<k)-1];
	}
}

signed main(){
    
    
	n=read(),m=read(),k=read();
	for (int i=1;i<=m;i++){
    
    
		int u=read(),v=read(),w=read();
		add_edge(u,v,w),add_edge(v,u,w);
	}
	for (int i=1;i<=k;i++){
    
    
		q[i]=read(),p[i]=read();
		tmp[++len]=q[i];
	}
	sort(tmp+1,tmp+len+1);
	len=unique(tmp+1,tmp+len+1)-tmp-1;
	for (int i=1;i<=k;i++)  q[i]=lower_bound(tmp+1,tmp+len+1,q[i])-tmp;
	for (int i=1;i<(1<<len);i++){
    
    
		Bin.clear();
		for (int j=1;j<=k;j++){
    
    
			if (i&(1<<(q[j]-1)))  Bin.push_back(p[j]);
		}
		g[i]=Dream_Tree::solve();
	}
	for (int i=0;i<(1<<len);i++){
    
    
		for (int j=i;j;j=(j-1)&i)  chkmin(g[j]+g[i^j],g[i]);
	}
	cout<<g[(1<<len)-1]<<endl;
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cherrt/article/details/119928672