POJ

来源:互联网 发布:网络桥架 编辑:程序博客网 时间:2024/06/08 09:14

传送门:POJ3662

题意:有n个点,其中m对可以连边,但是有不同的花费,现在要求将1和n连通,你可以先选k对点使其免费连上,剩下的需要你自己花钱,定义费用为需要你花钱的边中花钱最多的那条边,问最小费用是多少。

思路:显然尽量让长的边都免费是最优的,因此我们可以二分花费第k+1大的边(也就是答案),然后用最短路进行检查,看看能不能只用k条比mid费用大的边就能让1和n连通,由于比mid小的边我们可以随便用,因此可以将大于mid的边权值看成1,剩下的看成0,最终dis[i]就代表用多少比mid大的边能使1和i连通。


sb的我一开始还想用bfs去check。。

代码:

#include<stdio.h>#include<iostream>#include<algorithm>#include<string.h>#include<vector>#include<queue>#define ll long long#define pb push_back#define fi first#define se second#define pi acos(-1)#define inf 0x3f3f3f3f#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#define rep(i,x,n) for(int i=x;i<n;i++)#define per(i,n,x) for(int i=n;i>=x;i--)using namespace std;const int MAXN=100010;int gcd(int a,int b){return b?gcd(b,a%b):a;}struct P{int v, w;P(int _v, int _w) : v(_v), w(_w){}};vector<P> mp[MAXN];int n, m, k;queue<int> q;bool book[1100];int dis[MAXN];bool check(int mid){while(!q.empty())q.pop();memset(dis, inf , sizeof(dis));memset(book, 0, sizeof(book));q.push(1);dis[1] = 0;book[1]= 1;while(!q.empty()){int u = q.front(); q.pop();for(int i = 0; i < mp[u].size(); i++){int v = mp[u][i].v, w = mp[u][i].w;if(w > mid){if(dis[v] > dis[u] + 1){ dis[v] = dis[u] + 1;if(!book[v]){book[v] = 1;q.push(v);}}}else{if(dis[v] > dis[u]){ dis[v] = dis[u];if(!book[v]){book[v] = 1;q.push(v);}}}}book[u] = 0;}return dis[n] <= k;}int main(){int u, v, w;cin >> n >> m >> k;for(int i = 0; i < m; i++){scanf("%d %d %d", &u, &v, &w);mp[u].pb(P(v, w));mp[v].pb(P(u, w));}int l = 0, r = 1e6 + 10, mid;while(l <= r){mid = (l + r) >> 1;if(check(mid))r = mid - 1;elsel = mid + 1;}if(r + 1 > (int)1e6)r = -2;cout << r + 1 << endl; return 0;}


原创粉丝点击