【GDOI2014模拟】旅行 题解(水法)

【GDOI2014模拟】旅行

Description

从前有一位旅者,他想要游遍天下所有的景点。这一天他来到了一个神奇的王国:在这片土地上,有n个城市,从1到n进行编号。王国中有m条道路,第i条道路连接着两个城市ai,bi,由于年代久远,所有的道路都已经不能使用。如果要修复第i条道路,需要wi的时间。为了更好的旅行,旅者想要将某些道路修复,使得1号城市能够到达n号城市,2号城市能够到达n-1号城市..k号城市能够到达n-k+1号城市。为了满足他的要求,请问最少需要多少时间去修复道路。无解请输出-1。

Input

第一行:n,m,k 接下来m行:ai,bi,wi 含义如上所述。

Output

输出共一行:最少需要多少时间修复道路。如果始终无法满足旅者的要求,请输出-1。

Sample Input

5 5 2 1 3 4 3 5 2 2 3 1 3 4 4 2 4 3

Sample Output

9

Data Constraint

20%的数据满足:k ⇐ 2, n<= 10, m ⇐ 20 40%的数据满足:k ⇐ 3, n<=100, m<=1000 70%的数据满足:k<=4, n<=1000, m<=1000 100%的数据满足:k<=4, n<=10000, m<=10000, n >= 2*k, wi<= 1000, 1 ⇐ ai, bi ⇐ n

Hint

样例解释: 在这里插入图片描述

题解

考场上看到这题先是想到了最小生成树,然后乱搞,然后就没有然后了…… 正解似乎是斯坦纳树板子题,但我不会 下面提供一种连拍都过不了但是过掉数据的水法 我们发现k非常小,也就是说关键点个数非常少,于是我们可以将每对关键点的遍历顺序$k!$做一个全排列,之后在每一对点中跑一遍spfa,经过的边加到答案里面,然后全部赋值为0,最后取最小的答案 (什么?你问我这个操作怎么做?随便写个链表就行了) 错误性显然

CODE(水法)

#include<cstdio>
#include<string>
#include<queue>
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
#define R register int
#define N 10005
#define K 5
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
struct arr{int x,y,z;}bian[N];
struct G{int to,next,w;}e[N<<1];
int n,m,k,ans,f[K],cnt,head[N],dist[N],nxt[N][2];
bool change[K],bz[N];
inline void read(int &x)
{
	x=0;int f=1;char ch=getchar();
	while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();x*=f; 
}
inline void add(int u,int v,int w)
{
	e[++cnt].to=v;e[cnt].w=w;
	e[cnt].next=head[u];head[u]=cnt;
}
inline int spfa(int st,int en)
{
	queue<int>q;
	for (R i=1;i<=n;++i)
		dist[i]=inf,bz[i]=0;
	q.push(st);dist[st]=0;bz[st]=1;
	while (!q.empty())
	{
		int u=q.front();q.pop();
		for (R i=head[u];i!=-1;i=e[i].next)
		{
			int v=e[i].to;
			if (dist[v]>dist[u]+e[i].w)
			{
				dist[v]=dist[u]+e[i].w;nxt[v][0]=u;nxt[v][1]=i;
				if (!bz[v]) q.push(v),bz[v]=1; 
			}
		}
		bz[u]=0;
	}
	return dist[en];
}
inline void dg(int x)
{
	if (x>k)
	{
		cnt=-1;
		for (R i=1;i<=n;++i)
			head[i]=-1;
		for (R i=1;i<=m;++i)
			add(bian[i].x,bian[i].y,bian[i].z),add(bian[i].y,bian[i].x,bian[i].z);
		int sum=0;
		for (R i=1;i<=k;++i)
		{
			int st=f[i],en=n-f[i]+1,tot=spfa(st,en);
			if (tot==inf) return;sum+=tot;int now=en;
			while (now!=st)
			{
				e[nxt[now][1]].w=e[nxt[now][1]^1].w=0;now=nxt[now][0];
			}
		}
		ans=min(sum,ans);
		return;	
	}
	for (R i=1;i<=k;++i)
	{
		if (!change[i])
		{
			change[i]=1;f[x]=i;dg(x+1);change[i]=0;
		}
	}
}
int main()
{
	read(n);read(m);read(k);ans=inf;
	for (R i=1;i<=m;++i)
		read(bian[i].x),read(bian[i].y),read(bian[i].z);
	dg(1);
	if (ans==inf) printf("-1
");else printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/CMC-YXY/p/14983305.html