P1099 树网的核
NOIP 2007 提高第四题。
啊......我还是看了题解才做出来的。
这题乍一看毫无头绪,但是我们spy on一下,暗中观察发现:n才300!随便打暴力水过去啊!
然后,这破题怎么暴力?感觉我的spfa,dijkstra都WA2了...
最后还是跑去看了题解。
一步一步慢慢模拟就出来了。
首先,肯定要跑floyd的。
然后,我们居然还要个邻接表来存图......(用来dfs求直径)
无脑Floyd的同时,记录一条直径的起点,终点。
find_d求了一条直径上的所有点。
然后find_f求出了直径上每个点不超过s能去的最远点。
然后对于每段直径上小于s的路径,求出每个点的min的max作为偏心距,然后再求min。
然后输出,成功。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 int chart[301][301],n,s,top,d; 6 struct Edge 7 { 8 int u,v,len,next; 9 }edge[601]; 10 int point_e[301],d_f[301][2],topd;///0dian 1xiabiao 11 bool vis[301]; 12 void add(int x,int y,int z) 13 { 14 top++; 15 edge[top].u=x; 16 edge[top].v=y; 17 edge[top].len=z; 18 edge[top].next=point_e[x]; 19 point_e[x]=top; 20 return; 21 } 22 /// 23 bool find_d(int a,int b) 24 { 25 if(a==b) 26 { 27 d_f[++topd][0]=b; 28 return 1; 29 } 30 if(vis[a]) return 0; 31 vis[a]=1; 32 int i=point_e[a]; 33 while(i) 34 { 35 if(find_d(edge[i].v,b)) 36 { 37 d_f[++topd][0]=a; 38 vis[a]=0; 39 return 1; 40 } 41 i=edge[i].next; 42 } 43 vis[a]=0; 44 return 0; 45 } 46 void find_f(int k) 47 { 48 int i=k; 49 for(;i<=topd;i++) 50 { 51 if(chart[d_f[k][0]][d_f[i][0]]>s) break; 52 } 53 i--; 54 d_f[k][1]=i; 55 return; 56 } 57 int find_ans(int k) 58 { 59 int ans=0,now=9999998; 60 for(int i=1;i<=n;i++) 61 { 62 now=9999997; 63 for(int j=k;j<=d_f[k][1];j++) 64 { 65 now=min(now,chart[i][d_f[j][0]]); 66 } 67 ans=max(ans,now); 68 } 69 return ans; 70 } 71 int main() 72 { 73 memset(chart,0x3f,sizeof(chart)); 74 scanf("%d%d",&n,&s); 75 for(int i=1;i<=n;i++) chart[i][i]=0; 76 int x,y,z; 77 for(int i=1;i<n;i++) 78 { 79 scanf ("%d%d%d",&x,&y,&z); 80 chart[x][y]=chart[y][x]=z; 81 add(x,y,z); 82 add(y,x,z); 83 } 84 int da,db; 85 for(int k=1;k<=n;k++) 86 { 87 for(int i=1;i<=n;i++) 88 { 89 for(int j=1;j<=n;j++) 90 { 91 if(chart[i][j]>chart[i][k]+chart[k][j]) 92 { 93 chart[i][j]=chart[i][k]+chart[k][j]; 94 if(chart[i][j]>d) 95 { 96 d=chart[i][j]; 97 da=i;db=j; 98 } 99 } 100 } 101 } 102 } 103 /// 104 /** 105 for(int i=1;i<=n;i++) 106 { 107 for(int j=1;j<=n;j++) 108 { 109 printf("%d ",chart[i][j]); 110 } 111 printf("\n"); 112 } 113 */ 114 /// 115 find_d(da,db); 116 for(int i=1;i<=topd;i++) find_f(i); 117 /// 118 /** 119 for(int i=1;i<=topd;i++) printf("%d ",d_f[i][0]); 120 printf("\n"); 121 for(int i=1;i<=topd;i++) printf("%d ",d_f[i][1]); 122 */ 123 /// 124 int now,ans=9999999; 125 for(int i=1;i<=topd;i++) 126 { 127 now=find_ans(i); 128 //printf("find_ans(%d)=%d\n",i,now); 129 ans=min(ans,now); 130 } 131 printf("%d",ans); 132 return 0; 133 }
这个纯暴力模拟题居然是蓝题...说明了我的暴力功力还不够。以后还要练搜索剪枝的。先做点USACO吧。
(logeadd:133行代码怎么不能是蓝题了?好像有点道理啊...)