【SPFA+二分答案】BZOJ1614- [Usaco2007 Jan]Telephone Lines架设电话线
沉迷于刷水
以前的那个二分写法过不了QAQ 换了一种好像大家都比较常用的二分。原因还不是很清楚。
【题目大意】
给出一张图,可以将其中k条边的边权减为0,求1到n的路径中最长边的最小值。
【思路】
二分答案,即最长边的最小值x。对于每次check(x),我们将边权大于x的边设为1,边权小于等于x的边设为0,跑SPFA,结果相当于最少经过多少条边权大于x的边。如果SPFA结果>k,则不可行,否则可行。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 #include<queue> 8 using namespace std; 9 const int INF=1000000+5; 10 const int MAXN=1000+5; 11 struct edge 12 { 13 int to,dis; 14 }; 15 vector<edge> E[MAXN]; 16 int n,p,k; 17 int inque[MAXN],dis[MAXN]; 18 19 void addedge(int u,int v,int w) 20 { 21 E[u].push_back((edge){v,w}); 22 E[v].push_back((edge){u,w}); 23 } 24 25 void init() 26 { 27 scanf("%d%d%d",&n,&p,&k); 28 for (int i=1;i<=p;i++) 29 { 30 int u,v,w; 31 scanf("%d%d%d",&u,&v,&w); 32 addedge(u,v,w); 33 } 34 } 35 36 int check(int x) 37 { 38 queue<int> que; 39 memset(inque,0,sizeof(inque)); 40 memset(dis,0x7f,sizeof(dis)); 41 dis[1]=0,inque[1]=1; 42 que.push(1); 43 while (!que.empty()) 44 { 45 int head=que.front();que.pop(); 46 inque[head]=0; 47 for (int i=0;i<E[head].size();i++) 48 { 49 int nowlen,to=E[head][i].to; 50 if (E[head][i].dis>x) nowlen=1;else nowlen=0; 51 if (dis[head]+nowlen<dis[to]) 52 { 53 dis[to]=dis[head]+nowlen; 54 if (!inque[to]) 55 { 56 que.push(to); 57 inque[to]=1; 58 } 59 } 60 } 61 } 62 if (dis[n]>k) return 0;else return 1; 63 } 64 65 void solve() 66 { 67 int lb=0,ub=INF,ans=-1; 68 while (lb<=ub) 69 { 70 int mid=(lb+ub)>>1; 71 if (check(mid)) ub=mid-1,ans=mid; 72 else lb=mid+1; 73 } 74 printf("%d\n",ans); 75 } 76 77 int main() 78 { 79 init(); 80 solve(); 81 return 0; 82 }