Tokitsukaze and Rescue ( dfs+最短路递归路径 )
题意:节点数<=50的完全图,去掉k条边( 最大为5 ) 之后,1-n的最短路的最大值是多少。
思路:比赛一直往图论上想了,怎么也没想到一个合适的算法,结果是dfs暴力。以后可长点教训吧。
完全图,随机的数据,大体可以猜测最短路不会太长,所以只要每次跑一下最短路,取一条最短路出来,枚举删除最短路上的一条边,然后递归,变成删除 (k − 1) 条边的子问题。
注意:在每一层dfs里都需要记录最短路的边,如果在外面定义了数组存,就给覆盖了。所以必须在dfs里面定义变量。
tip:最短路的记录,用一个last数组,在松弛条件里加上就可以记录了。好像没必要找出所有的最短路。
代码:
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
using namespace std;
int mp[55][55],dis[55],n,k,via[55],last[55],ans;
struct node {
int v,date;
}t,d;
bool operator < ( const node&a, const node&b )
{
return a.date>b.date;
}
void dijstra( int v0 )
{
priority_queue<node> Q;
memset(via,0,sizeof(via));
memset(dis,inf,sizeof(dis));
memset(last,0,sizeof(last));
dis[v0] = 0;
t.v=v0;t.date=0;
Q.push(t);
while ( !Q.empty() ) {
if ( via[Q.top().v]==1 ) {
Q.pop(); continue;
}
t = Q.top();Q.pop();
int u = t.v;
dis[u] = t.date;
via[u] = 1;
for ( int i=1; i<=n; i++ ) {
if ( mp[u][i]>=inf ) continue;
if ( via[i]==0 && dis[i]>dis[u]+mp[u][i] ) {
dis[i] = dis[u]+mp[u][i];
last[i] = u;
d.v = i; d.date=dis[i];
Q.push(d);
}
}
}
}
void dfs( int pos )
{
dijstra(1);
if ( pos==k ) {
ans = max(ans,dis[n]);
return ;
}
vector<int> a;a.clear();
int x = n;a.push_back(x);
while ( last[x]!=0 ) {
a.push_back( last[x] );
x = last[x];
}
for ( int i=0; i<a.size()-1; i++ ) {
int u = a[i], v=a[i+1];
int tmp = mp[u][v];
mp[u][v] = mp[v][u] = inf;
dfs(pos+1);
mp[u][v] = mp[v][u] = tmp;
}
}
signed main()
{
int T;cin>>T;
while ( T-- ) {
cin>>n>>k;
for ( int i=1; i<=n; i++ ) mp[i][i]=0;
for ( int i=0; i<n*(n-1)/2; i++ ) {
int u,v,w;scanf("%lld %lld %lld",&u,&v,&w);
mp[u][v] = mp[v][u] = w;
}
ans = 0;
dfs(0);
cout << ans <<endl;
}
return 0;
}