题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26881
思路:我们可以二分最大危险度,然后建图,由于每个休息点只能用一次,就要拆点,将每个休息点拆点,边容量为1,代表只能使用一次,然后跑最大流验证。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<queue> 6 #include<cmath> 7 using namespace std; 8 #define MAXN 222 9 #define MAXM 222222 10 #define inf 1<<30 11 #define FILL(a,b) memset(a,b,sizeof(a)) 12 13 struct Edge{ 14 int v,cap,next; 15 }edge[MAXM]; 16 17 int n,m,vs,vt,k,NV,NE; 18 int head[MAXN]; 19 20 void Insert(int u,int v,int cap) 21 { 22 edge[NE].v=v; 23 edge[NE].cap=cap; 24 edge[NE].next=head[u]; 25 head[u]=NE++; 26 27 edge[NE].v=u; 28 edge[NE].cap=0; 29 edge[NE].next=head[v]; 30 head[v]=NE++; 31 } 32 33 int level[MAXN],gap[MAXN]; 34 void bfs(int vt) 35 { 36 FILL(level,-1); 37 FILL(gap,0); 38 queue<int>que; 39 level[vt]=0; 40 gap[0]++; 41 que.push(vt); 42 while(!que.empty()){ 43 int u=que.front(); 44 que.pop(); 45 for(int i=head[u];i!=-1;i=edge[i].next){ 46 int v=edge[i].v; 47 if(level[v]!=-1)continue; 48 level[v]=level[u]+1; 49 gap[level[v]]++; 50 que.push(v); 51 } 52 } 53 } 54 55 int pre[MAXN],cur[MAXN]; 56 int SAP(int vs,int vt) 57 { 58 bfs(vt); 59 memcpy(cur,head,sizeof(head)); 60 int u=pre[vs]=vs,aug=inf,maxflow=0; 61 gap[0]=NV; 62 while(level[vs]<NV){ 63 bool flag=false; 64 for(int &i=cur[u];i!=-1;i=edge[i].next){ 65 int v=edge[i].v; 66 if(edge[i].cap>0&&level[u]==level[v]+1){ 67 flag=true; 68 aug=min(aug,edge[i].cap); 69 pre[v]=u; 70 u=v; 71 if(v==vt){ 72 maxflow+=aug; 73 for(u=pre[u];v!=vs;v=u,u=pre[u]){ 74 edge[cur[u]].cap-=aug; 75 edge[cur[u]^1].cap+=aug; 76 } 77 aug=inf; 78 } 79 break; 80 } 81 } 82 if(flag)continue; 83 int minlevel=NV; 84 for(int i=head[u];i!=-1;i=edge[i].next){ 85 int v=edge[i].v; 86 if(edge[i].cap>0&&level[v]<minlevel){ 87 minlevel=level[v]; 88 cur[u]=i; 89 } 90 } 91 if(--gap[level[u]]==0)break; 92 level[u]=minlevel+1; 93 gap[level[u]]++; 94 u=pre[u]; 95 } 96 return maxflow; 97 } 98 99 struct Path{ 100 int u,v,d; 101 }path[MAXM]; 102 103 void Build(int limit) 104 { 105 NE=0; 106 memset(head,-1,sizeof(head)); 107 vs=0,vt=2*n+3,NV=2*n+4; 108 for(int i=0;i<m;i++){ 109 if(path[i].d<=limit)Insert(path[i].u+n+2,path[i].v,1); 110 } 111 for(int i=1;i<=n;i++)Insert(i,i+n+2,1); 112 Insert(vs,vs+n+2,11); 113 Insert(n+1,vt,11); 114 } 115 116 117 int main() 118 { 119 int _case,u,v,d,low,high,mid,ans,t=1; 120 scanf("%d",&_case); 121 while(_case--){ 122 scanf("%d%d",&n,&m); 123 low=inf,high=0; 124 for(int i=0;i<m;i++){ 125 scanf("%d%d%d",&path[i].u,&path[i].v,&path[i].d); 126 if(path[i].u>path[i].v)swap(path[i].u,path[i].v); 127 //cout<<path[i].u<<"&&&&"<<path[i].v<<endl; 128 low=min(low,path[i].d); 129 high=max(high,path[i].d); 130 } 131 // cout<<low<<"**"<<high<<endl; 132 scanf("%d",&k); 133 ans=inf; 134 while(low<=high){ 135 mid=(low+high)>>1; 136 Build(mid); 137 if(SAP(vs,vt)>=k){ 138 ans=mid; 139 high=mid-1; 140 }else 141 low=mid+1; 142 } 143 printf("Case %d: ",t++); 144 if(ans!=inf){ 145 printf("%d ",ans); 146 }else 147 puts("no solution"); 148 } 149 return 0; 150 }