T3 C
题意
给出无向图,
n
n
n点
m
m
m边,求从
1
1
1到
n
n
n经过
k
k
k条边的简单最短路
简单最短路定义为无重边,无重点路径
min
(
n
,
m
,
k
)
≤
5
\min(n,m,k)\le 5
min(n,m,k)≤5
暴力
比较优秀的79pts暴力
#include<bits/stdc++.h>
using namespace std;
#define in Read()
int Read(){
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
#define pb push_back
#define mp make_pair
typedef pair<int,int> anti;
const int N=1e6+5;
int n,m,k,dis[N][100];
vector<anti>G[N];
struct node{
int step,dis,u;
set<int>s;
void clear(){
step=0,dis=0,u=0;
s.clear();
}
void print(){
printf("step=%d dis=%d u=%d size=%d ",step,dis,u,s.size());
for(int i=1;i<=n;++i) if(s.find(i)!=s.end()) printf("%d ",i);
puts("");
return;
}
friend inline bool operator < (const node &a,const node &b){
if(a.step!=b.step) return a.step>b.step;
else if(a.dis!=b.dis) return a.dis>b.dis;
else return a.s.size()>b.s.size();
}
}mone,mony;
priority_queue<node>q;
int Dijkstra(){
memset(dis,0x3f,sizeof dis);
dis[1][0]=0;
mone.step=0;
mone.dis=0;
mone.u=1;
mone.s.insert(1);
q.push(mone);
while(!q.empty()){
mony=q.top();q.pop();
int u=mony.u,st=mony.step;
if(st==k&&u==n) return mony.dis;
if(st> k) return -1;
for(int e=0;e<G[u].size();++e){
int v=G[u][e].first,w=G[u][e].second;
if(dis[v][st+1]>dis[u][st]+w){
dis[v][st+1]=dis[u][st]+w;
if(mony.s.find(v)==mony.s.end()){
mone=mony;
mone.dis=dis[v][st+1];
mone.step++;
mone.u=v;
mone.s.insert(v);
q.push(mone);
}
}
}
}
return -1;
}
int main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
n=in,m=in,k=in;
for(int i=1;i<=m;++i){
int u=in,v=in,w=in;
G[u].pb(mp(v,w));
G[v].pb(mp(u,w));
}
printf("%d\n",Dijkstra());
return 0;
}
题解
读不懂这个限制条件就很淦
首先显然
n
≤
k
n\le k
n≤k和
m
≤
k
m\le k
m≤k时无解
因此只需要考虑
k
≤
5
k\le 5
k≤5的情况
如果
k
k
k不足
5
5
5,添加一些点
n
+
1
,
n
+
2
,
.
.
.
n+1,n+2,...
n+1,n+2,...凑到
5
5
5
讨论
k
=
5
k=5
k=5就行了
每个点要记录前三长的于1相连的长度,防止重复
代码实现难度较高,弃
没有记前三长的54pts
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
int Read(){
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<3)+(i<<1)+ch-48,ch=getchar();
return i*f;
}
void Min(int &a,int b){if(a>b) a=b;}
const int N=1e6+5,inf=1e18;
int n,m,K;
int tot,first[N];
int dis[N][5][5];
struct Edge{
int wei,aim,nxt,ori;
}e[N<<1];
bool cmp(Edge u,Edge v){return u.wei<v.wei;}
void ljb(int u,int v,int w){
++tot;
e[tot].nxt=first[u];
first[u]=tot;
e[tot].aim=v;
e[tot].ori=u;
e[tot].wei=w;
return;
}
void DFS(int u,int fa,int s,int k){
// printf("%d %d %d %d\n",s,u,fa,k);
if(k>=3) return;
for(int ed=first[u];ed;ed=e[ed].nxt){
int v=e[ed].aim;
if(v==fa||v==s) continue;
Min(dis[v][k+1][!(s==1)],dis[u][k][!(s==1)]+e[ed].wei);
DFS(v,u,s,k+1);
}
return;
}
signed main(){
n=in,m=in,K=in;
if(n<=K||m<K){
puts("-1");
return 0;
}
for(int i=1;i<=m;++i){
int u=in,v=in,w=in;
ljb(u,v,w);
ljb(v,u,w);
}
for(int i=1;i<=5-K;++i){
ljb(n+i,n+i-1,0);
ljb(n+i-1,n+i,0);
}
n+=5-K;
for(int i=1;i<=n;++i)
for(int j=1;j<=3;++j)
dis[i][j][0]=dis[i][j][1]=inf;
dis[1][1][0]=0;
DFS(1,0,1,1);
dis[n][1][1]=0;
DFS(n,0,n,1);
int ans=inf;
for(int i=1;i<=tot;++i){
Edge ed=e[i];
if(dis[ed.ori][3][0]!=inf&&dis[ed.aim][3][1]!=inf)
Min(ans,dis[ed.ori][3][0]+dis[ed.aim][3][1]+ed.wei);
}
if(ans==inf) puts("-1");
else printf("%lld\n",ans);
// for(int i=1;i<=n;++i){
// printf("%lld: ",i);
// for(int j=1;j<=3;++j)
// printf("%lld ",dis[i][j][0]);
// puts("");
// }
// for(int i=1;i<=n;++i){
// printf("%lld: ",i);
// for(int j=1;j<=3;++j)
// printf("%lld ",dis[i][j][1]);
// puts("");
// }
// for(int i=1;i<=n;++i) printf("%d ",first[i]); puts("");
return 0;
}