原题
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
样例解释:
题目大意
给出n个点,m条带权双向边,和一个整数k。
k≤4,n≤10000,m≤10000
让你连接其中一些边,使得1号城市能够到达n号城市,2号城市能够到达n-1号城市…k号城市能够到达n-k+1号城市。
求最少的边权。若不能满足则输出-1。
题解
用每一种1~k的顺序(即 K的全排列)来对每一个 i(1 ≤ i ≤ k)操作。
用单源最短路算法SPFA求出点 i 到点 n-i+1 的最短距离。
再把最短路径上的每一条边的权值赋为0。
统计最小答案即可。以下为代码:
Code
#include<cstdio>
#include<cstring>
using namespace std;
const int N=10001;
int ans,tot,dis[N],f[N],que[3*N],h[24][4];
int first[N],next[2*N],en[2*N],w[2*N],w1[2*N];
bool bz[N];
inline int read()
{
int data=0; char ch=0;
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9') data=data*10+ch-'0',ch=getchar();
return data;
}
inline void add(int x,int y,int z)
{
next[++tot]=first[x];
first[x]=tot;
en[tot]=y;
w[tot]=z;
}
inline void dfs(int x,int y)
{
if(x==y)
{
for(int i=0;i<y;i++) h[tot][i]=f[i+1];
tot++;
return;
}
for(int i=1;i<=y;i++)
if(!bz[i])
{
bz[i]=true;
f[++f[0]]=i;
dfs(x+1,y);
f[f[0]--]=0;
bz[i]=false;
}
}
int main()
{
int n=read(),m=read(),q=read();
for(int i=1;i<=m;i++)
{
int x=read(),y=read(),z=read();
add(x,y,z);
add(y,x,z);
}
tot=0;
dfs(0,q); //全排列
ans=1e7;
for(int i=0;i<tot;i++)
{
int sum=0,w1[2*N];
memcpy(w1,w,sizeof(w1));
for(int j=0;j<q;j++)
{
memset(dis,60,sizeof(dis));
memset(bz,false,sizeof(bz));
memset(f,0,sizeof(f));
int head=dis[h[i][j]]=0,tail=1;
que[tail]=h[i][j];
while(head<tail)
{
bz[que[++head]]=false;
for(int k=first[que[head]];k;k=next[k])
if(dis[en[k]]>dis[que[head]]+w1[k])
{
dis[en[k]]=dis[que[head]]+w1[k];
f[en[k]]=que[head];
if(!bz[en[k]]) bz[que[++tail]=en[k]]=true;
}
} //此处为SPFA
if(dis[n-h[i][j]+1]>1e7)
{
printf("-1");
return 0;
} //无解
sum+=dis[n-h[i][j]+1];
for(int t=n-h[i][j]+1;t!=f[h[i][j]];t=f[t])
{
for(int k=first[f[t]];k;k=next[k])
if(en[k]==t)
{
w1[k]=0;
break;
}
for(int k=first[t];k;k=next[k])
if(en[k]==f[t])
{
w1[k]=0;
break;
}
} //边赋为0
}
if(sum<ans) ans=sum;
}
printf("%d",ans);
return 0;
}