严格的意思是每个节点只允许访问一次。
解法:二分k短路路长。
注意点: 观察数据范围,应该是稠密图,比较适合矩阵,测了一下矩阵比邻接表快100+ms。 另外可以先做一次spfa预处理,利用节点到t的距离剪枝,这能从300+ms优化到31ms。
TLE点:我之前二分的时候,每次是求出满足要求的路径个数,TLE 3。 看了别人代码发现每次只要找到K条路径就行,看下数据,k<=500,这样时间优化的还是挺多的...(对数据范围还是不敏感啊,只知道yy,不知道看数据范围T_T...)
矩阵+spfa优化 31ms
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define INF 0x7ffffff
int e[105][105],n,m,s,t,k,limit;
bool visited[105];
int path[105],pcnt,cnt,dist[105];
bool inq[105];
bool flag;
void spfa()
{
int i,u,v,d;
for(i=1;i<=n;++i)
dist[i]=INF;
memset(inq,false,sizeof(inq));
dist[t]=0;inq[t]=true;
deque<int> q;
q.push_front(t);
while(!q.empty())
{
u=q.front();inq[u]=false;q.pop_front();
for(i=1;i<=n;++i)
{
if(e[u][i]!=0)
{
d=e[u][i];v=i;
if(dist[u]+d<dist[v])
{
dist[v]=dist[u]+d;
if(!inq[v])
{
inq[v]=true;
if(!q.empty()&&dist[v]<=dist[q.front()])
q.push_front(v);
else
q.push_back(v);
}
}
}
}
}
}
void dfs(int u,int sum)
{
visited[u]=true;
if(u==t)
{
if(sum<=limit)
cnt++;
if(cnt>=k)
flag=true;
visited[u]=false;
return ;
}
int v,i,d;
if(sum+dist[u]>limit)
{
visited[u]=false;
return ;
}
for(i=1;i<=n;++i)
{
if(e[u][i]!=0&&!visited[i])
{
d=e[u][i];
if(sum+d<=limit)
dfs(i,sum+d);
if(flag)
{
visited[u]=false;
return ;
}
}
}
visited[u]=false;
return ;
}
void find_path(int u,int sum)
{
visited[u]=true;path[pcnt++]=u;
if(u==t)
{
if(sum==limit)
{
printf("%d %d\n",limit,pcnt);
for(int i=0;i<pcnt;++i)
printf("%d%c",path[i],i==pcnt-1?'\n':' ');
visited[u]=false;pcnt--;
flag=true;
return ;
}
else
{
visited[u]=false;pcnt--;
return ;
}
}
int i,d;
if(sum+dist[u]>limit)
{
visited[u]=false;pcnt--;
return ;
}
for(i=1;i<=n;++i)
{
if(e[u][i]!=0&&!visited[i])
{
d=e[u][i];
if(sum+d<=limit)
find_path(i,sum+d);
if(flag)
{
visited[u]=false;
pcnt--;
return ;
}
}
}
visited[u]=false;pcnt--;
return ;
}
int main()
{
int i,u,v,cost,l,r=0,mid;
memset(e,0,sizeof(e));
memset(visited,false,sizeof(visited));
pcnt=0,cnt=0;
scanf("%d %d %d",&n,&m,&k);
for(i=0;i<m;++i)
{
scanf("%d %d %d",&u,&v,&cost);
e[u][v]=e[v][u]=cost;
r+=cost;
}
scanf("%d %d",&s,&t);
spfa();
l=0;
while(l!=r)
{
mid=(l+r)>>1;
limit=mid;
cnt=0,flag=false;
dfs(s,0);
if(!flag)
{
l=mid+1;
}
else
{
r=mid;
}
}
limit=l,flag=false;
find_path(s,0);
return 0;
}
邻接表 无优化 479ms。。。
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define INF 0x7ffffff
struct edge
{
int to,w,next;
}ee[10010];
int e[105],ecnt,s,t,k,limit,n,m;
bool visited[105];
int path[105],pcnt,cnt;
bool flag;
void addedge(int u,int v,int cost)
{
ee[ecnt].to=v;ee[ecnt].w=cost;ee[ecnt].next=e[u];e[u]=ecnt;
ecnt++;
ee[ecnt].to=u;ee[ecnt].w=cost;ee[ecnt].next=e[v];e[v]=ecnt;
ecnt++;
}
void dfs(int u,int sum)
{
if(u==t)
{
if(sum<=limit)
{
cnt++;
if(cnt>=k)
flag=true;
return ;
}
else
return ;
}
visited[u]=true;
int pt,v,d;
for(pt=e[u];pt!=-1;pt=ee[pt].next)
{
v=ee[pt].to;d=ee[pt].w;
if(!visited[v])
{
if(sum+d<=limit)
dfs(v,sum+d);
if(flag)
{
visited[u]=false;
return ;
}
}
}
visited[u]=false;
return ;
}
bool find_path(int u,int sum)
{
path[pcnt++]=u;
visited[u]=true;
if(u==t)
{
if(sum==limit)
{
printf("%d %d\n",limit,pcnt);
for(int i=0;i<pcnt;++i)
printf("%d%c",path[i],i==pcnt-1?'\n':' ');
pcnt--;
visited[u]=false;
return true;
}
else
{
visited[u]=false;pcnt--;
return false;
}
}
int pt,v,d;
for(pt=e[u];pt!=-1;pt=ee[pt].next)
{
v=ee[pt].to;d=ee[pt].w;
if(!visited[v])
{
if(sum+d<=limit)
{
if(find_path(v,sum+d)==true)
{
pcnt--;
visited[u]=false;
return true;
}
}
}
}
visited[u]=false;pcnt--;
return false;
}
int main()
{
int i,u,v,cost;
int l,r,mid,tt;
r=0;
scanf("%d %d %d",&n,&m,&k);
memset(e,-1,sizeof(e));
ecnt=0;
for(i=0;i<m;++i)
{
scanf("%d %d %d",&u,&v,&cost);
addedge(u,v,cost);
r+=cost;
}
scanf("%d %d",&s,&t);
l=0;
while(l!=r)
{
mid=(l+r)>>1;
limit=mid;
memset(visited,false,sizeof(visited));
flag=false,cnt=0;
dfs(s,0);
// printf("limit==%d,ans==%d\n",limit,flag);
if(!flag)
{
l=mid+1;
}
else
{
r=mid;
}
}
limit=l;
memset(visited,false,sizeof(visited));
pcnt=0;
find_path(s,0);
return 0;
}