题目:http://poj.org/problem?id=3662
题意:FJ要从1到N接电话线,电话公司可以免除K条的费用,求让需付费的电话线中的最大值在各种方案中最小的值,并输出。
我用的是二分+Dijkstra+二次建图的方法:
假设A是可行解,即路径上边权最大值为A,则该路径上边权大于A的边一定小于等于K条。
若A不是最优解,那么必然B<A,是的路径上边权大于B的边小于等于K。
于是我们可以二分答案,得到一个值X,将所有小于等于X的边变为0,大于X的边变为1。
做最短路,则1到N的距离就是所用权值大于X边的条数。如果小于等于K,则是一个可行解。
View Code
#include<stdio.h>
#include<algorithm>
#include<queue>
#include<string.h>
//#include<conio.h>
using namespace std;
typedef int T;
const T INF=0x3f3f3f3f;
const int NODE_MAX = 1005;
const int EDGE_MAX = 10000*2+5;
T weight[NODE_MAX+10];
int head[NODE_MAX+10];
T dis[NODE_MAX+10];
int vis[NODE_MAX+10];
int sta,ed;
int node_num,edge_num;
int num = 0;
int a[EDGE_MAX], b[EDGE_MAX], c[EDGE_MAX], csort[EDGE_MAX];
struct Node
{
T dist;
int sta;
Node(){};
Node(int a,T b):sta(a),dist(b){};
bool operator<(const Node a)const
{
return dist > a.dist;
}
};
struct Edge
{
int ed;
int nxt;
T cost;
}edge[EDGE_MAX];
void add_edge(int st,int ed,T cost)
{
edge[++num].ed = ed;
edge[num].cost = cost;
edge[num].nxt = head[st];
head[st] = num;
}
int dijkstra(int sta)
{
priority_queue<Node>que;
while(!que.empty()) que.pop();
memset(vis,0,sizeof(vis));
for(int i=0;i<=node_num;i++)
dis[i] = INF;
dis[sta]=0;
Node node_temp;
que.push(Node(sta,0));
while(!que.empty())
{
node_temp = que.top();
que.pop();
if(vis[node_temp.sta]) continue;
vis[node_temp.sta]=1;
for(int i=head[node_temp.sta]; i!=-1; i=edge[i].nxt)
{
if(dis[edge[i].ed] > node_temp.dist + edge[i].cost)
{
dis[edge[i].ed] = node_temp.dist + edge[i].cost;
que.push(Node(edge[i].ed,dis[edge[i].ed]));
}
}
}
return 1;
}
int main()
{
//freopen("D:/a.txt", "r", stdin);
int k, i, j, max, min, ans=INF, csort_num=1, ok, mid, oks=-1, flag=1;
scanf("%d%d%d", &node_num, &edge_num, &k);
memset(csort, 0, sizeof(csort));
for (i=1;i<=edge_num;i++)
{
scanf("%d%d%d", &a[i], &b[i], &c[i]);
{
ok=1;
for (j=1;j<=csort_num;j++)
{
if (c[i]==csort[j])
{
ok=0;
break;
}
}
if (ok)
csort[csort_num++]=c[i];
}
}
sort(csort, csort+csort_num);
max=csort_num-1;
min=0;
while (max>=min)
{
memset(dis, 0, sizeof(dis));
memset(head, -1, sizeof(head));
mid=(max+min)/2;
num=0;
for (i=0;i<=edge_num;i++)
{
if (c[i]>csort[mid])
{
add_edge(a[i], b[i], 1);
add_edge(b[i], a[i], 1);
}
else
{
add_edge(a[i], b[i], 0);
add_edge(b[i], a[i], 0);
}
}
dijkstra(1);
if (mid==0 || mid==csort_num-1)
{
flag=dis[node_num];
}
if (dis[node_num]>k)
{
min=mid+1;
oks=dis[node_num];
}
else
{
if (ans>csort[mid])
{
ans=csort[mid];
oks=dis[node_num];
}
max=mid-1;
}
}
if (flag==0)
printf("0\n");
else if (flag<INF && ans<INF)
printf("%d\n", ans);
else
printf("-1\n");
//getch();
return 0;
}