ovo这题没有靠谱的多项式复杂度的做法?!
好吧我也不知道该怎么做,于是学了一个大佬的Floyd玄学算法。
具体的实现还是很简单的,就是每次使用Floyd更新,必须要满足以下情况:
1.当前三个点文化不互相排斥
2.通往k(用于更新的点)的道路上所经过的文化与当前文化不互相排斥
3.距离更小
注意使用g[i][j][k]表示从i到j的路上排斥k文化,每次在更新的时候使用按位或来更新。
这样就可以做了……orz
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<queue> #include<set> #define rep(i,a,n) for(int i = a;i <= n;i++) #define per(i,n,a) for(int i = n;i >= a;i--) #define enter putchar(' ') using namespace std; typedef long long ll; const int M = 50005; const int INF = 10000000; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { ans *= 10; ans += ch - '0'; ch = getchar(); } return ans * op; } int n,k,m,s,t,c[105],a[105][105],dis[105][105],u,v,d; bool g[105][105][105]; void floyd() { rep(k,1,n) rep(i,1,n) rep(j,1,n) { if(a[c[k]][c[i]] || a[c[j]][c[k]]) continue;//不符合第一种情况 if(g[i][k][c[j]] || g[k][j][c[i]]) continue;//不符合第二种情况(注意这里不要把开始城市和结束城市搞混) if(dis[i][k] + dis[k][j] < dis[i][j]) { rep(t,1,n) g[i][j][t] = g[i][k][t] | g[k][j][t];//枚举每一种文化并且进行更新 g[i][j][c[k]] = 1; dis[i][j] = dis[i][k] + dis[k][j];//更新距离 } } } int main() { n = read(),k = read(),m = read(),s = read(),t = read(); rep(i,1,n) rep(j,1,n) dis[i][j] = INF; rep(i,1,n) c[i] = read(),dis[i][i] = 0; rep(i,1,k) rep(j,1,k) a[i][j] = read(); rep(i,1,m) { u = read(),v = read(),d = read(); if(!a[c[v]][c[u]] && c[u] != c[v]) dis[u][v] = min(dis[u][v],d); if(!a[c[u]][c[v]] && c[u] != c[v]) dis[v][u] = min(dis[v][u],d);//只有在符合条件的时候才更新距离 } rep(i,1,n) rep(j,1,n) g[i][j][c[i]] = 1,g[i][j][c[j]] = 1;//设置路径上的文化排斥 floyd(); if(dis[s][t] == INF) printf("-1 "); else printf("%d ",dis[s][t]); return 0; }