CF1204(最短路+思维)
Anna, Svyatoslav and Maps - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
首先用floyd跑一遍最短路。
对于p序列的两个点:如果 dis[p[i]][p[j]] = j-i,则序列p是经过 p[i]~p[j]的最短路.
假设现在存入 v 数组的最后一个点是p[i],找到p[i]后第一个点,使得 dis[p[i]][p[j]] < j - i,此时把 p[j]存入v数组,就不满足题意的:p是按顺序经过v的最短路径之一。
显然p[i+1],p[i+2]~p[j-1]是符合v数组的条件的,但为了让 v 的长度最短,我们只用将 p[j-1] 存入v数组,这样同时满足 dis[p[i]][p[j-1]] = (j-1)-i,dis[p[j-1]][p[j]]=j-(j-1)。
最后再将p[n]存入v数组。
Code:
#include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #define pb push_back #define popb pop_back #define fi first #define se second const int N=150; const int M=1e6+10; const int inf=0x3f3f3f3f; //const ll INF=0x3ffffffffffff; int T,n,m,dis[N][N],p[M]; char s[N][N]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int main() { // freopen("","r",stdin); // freopen("","w",stdout); n=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=inf; for(int i=1;i<=n;i++) dis[i][i]=0; for(int i=1;i<=n;i++) scanf("%s",s[i]+1); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(s[i][j]=='1') dis[i][j]=1; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); m=read(); for(int i=1;i<=m;i++) p[i]=read(); vector<int> v; v.pb(1); for(int i=2;i<=m;i++) if(dis[p[v.back()]][p[i]]<i-v.back()) v.pb(i-1); v.pb(m); printf("%d\n",v.size()); for(auto x:v) printf("%d ",p[x]); return 0; }