24 星球的末日
【问题描述】
24 星球的世界末日就要到了 , 可是诺亚方舟还没有制造完成 。 为了制造诺亚
方舟这个星球上的所有国家都站在统一战线 。 现在一共有n个国家 , 一个国家到
另一个国家都有一条且仅有一条通信渠道,且这个渠道有一个距离,这样就形
成了一个有向完全图。 。 世界末日的预兆已经来了 , 世界上很多东西都在遭到不
明原因的破坏,包括这些通信渠道。现在为了联合制造出诺亚方舟,需要统计
所有国家对 (a到b和b到a是不同的 ) 之间通信最短距离之和 。( ( 例如只有两个星
球 ,a到b与b 到a的距离都是1, 则最短距离和为2。) ) 可是每隔一段时间就有一些
渠道会被破坏,现在 24 星球的首领 大龙 急需要你来解决这个问题。
【输入文件】
读入文件 destroy.in
对于每组数据 , 第一行是一个n, 表示有n个国家 , 接下来有n行 , 每有n 个 非
负 整数。第i行第j 列的数字表示国家i i 到国家j j 的通信渠道距离(距离不大于
10000 ) 。 接下来是一个数字m, 表示在可以预知的未来中会有m次破坏会施加到
通信渠道中 , 每次破坏只能破坏一条渠道 , 一条渠道可以被破坏多次, , 但是第
一次破坏这条渠道就无法再发送信息 。 接下来有m行 , 每行两个整数a、b, 表示
国家a到国家b的通信渠道遭到破坏。
【输出文件】
输出文件 destroy.out
对于每组数据 , 输出m m 行 , 第i i 行表示第i i 次破坏后对应的答案是多少 。 如果
存在两个国家无法相互到达,输出1 1 NF 。
【输入样例】
3
0 1 1
1 0 1
1 1 0
4 4
1 2
1 2
2 3
2 3
【输出样例】
7
7
8
1NF
【数据规模】
40% 的数据中 1<n<=50,1<m<=50;
100% 的数据中 1<n<=200,1<m<=200 。
————————————————————————————题解
删边有点麻烦,所以我们一次性读入m个询问,离线处理,把所有边删除,倒着加上一条条边,回溯状态
我们加上第m条边时,我们到达的就是m-1的状态,加上第m-1条边时,就是m-2询问的状态……加上第2条边时,就是1询问的状态
枚举i=1->n j=1->n 用一条边u,v更新g[i][j]=min(g[i][j],g[i][u]+val(u,v)+g[v][j]
同时因为边可能重复被删,用一个next数组记录这条边最早被删掉的时刻,样例中next[2]=1,如果next不为0,当前状态的边是无法复原的,所以直接由上一个时刻过继过来就可以了
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <queue> 6 #include <set> 7 #include <vector> 8 #include <string.h> 9 #include <cmath> 10 #define siji(i,x,y) for(int i=(x);i<=(y);++i) 11 #define gongzi(j,x,y) for(int j=(x);j>=(y);--j) 12 #define xiaosiji(i,x,y) for(int i=(x);i<(y);++i) 13 #define sigongzi(j,x,y) for(int j=(x);j>(y);--j) 14 #define inf 0x3f3f3f3f 15 #define ivorysi 16 #define mo 97797977 17 #define hash 974711 18 #define base 47 19 #define MAXN 30005 20 #define fi first 21 #define se second 22 #define pii pair<int,int> 23 #define eps 1e-8 24 typedef long long ll; 25 using namespace std; 26 int n,m; 27 int f[205][205]; 28 int g[205][205]; 29 int a[205],b[205],ans[205],next[205]; 30 bool flag=0; 31 void solve() { 32 scanf("%d",&n); 33 siji(i,1,n) { 34 siji(j,1,n) { 35 scanf("%d",&f[i][j]); 36 g[i][j]=f[i][j]; 37 } 38 } 39 scanf("%d",&m); 40 siji(i,1,m) { 41 scanf("%d%d",&a[i],&b[i]); 42 g[a[i]][b[i]]=-1; 43 } 44 siji(k,1,n) { 45 siji(i,1,n) { 46 siji(j,1,n) { 47 if(g[i][k]==-1 || g[k][j]==-1) continue; 48 int x=g[i][k]+g[k][j]; 49 if(g[i][j]==-1) { 50 g[i][j]=x; 51 } 52 else { 53 g[i][j]=min(x,g[i][j]); 54 } 55 } 56 } 57 } 58 siji(i,1,m) { 59 siji(j,i+1,m) {//这里打错了一次变量名 60 if(a[i]==a[j] && b[i]==b[j]) { 61 if(next[j]==0) next[j]=i; 62 else if(next[j] > i) next[j]=i; 63 } 64 } 65 } 66 siji(i,1,n) { 67 siji(j,1,n) { 68 if(g[i][j]==-1) {ans[m]=-1;goto s;} 69 ans[m]+=g[i][j]; 70 } 71 } 72 s: 73 gongzi(i,m,2) { 74 if(next[i]!=0) {ans[i-1]=ans[i];continue;} 75 /* 76 更新时不要直接g[a[i]][b[i]]=f[a[i]][b[i]] 77 因为g[a[i]][b[i]]可能小于f[a[i]][b[i]] 78 这样会得到错解 79 */ 80 siji(j,1,n) { 81 siji(k,1,n) { 82 83 if(g[j][a[i]] == -1 || g[b[i]][k] == -1) continue; 84 int x=g[j][a[i]]+f[a[i]][b[i]]+g[b[i]][k]; 85 if(g[j][k]==-1) { 86 g[j][k]=x; 87 } 88 else { 89 g[j][k]=min(g[j][k],x); 90 } 91 } 92 } 93 siji(j,1,n) { 94 siji(k,1,n) { 95 if(g[j][k]==-1) {ans[i-1]=-1;goto t;} 96 ans[i-1]+=g[j][k]; 97 } 98 } 99 t:; 100 } 101 siji(i,1,m) { 102 if(ans[i]==-1) puts("1NF"); 103 else { 104 printf("%d ",ans[i]); 105 } 106 } 107 } 108 int main(int argc, char const *argv[]) 109 { 110 #ifdef ivorysi 111 freopen("destroy.in","r",stdin); 112 freopen("destroy.out","w",stdout); 113 #else 114 freopen("f1.in","r",stdin); 115 #endif 116 solve(); 117 return 0; 118 }