zoukankan      html  css  js  c++  java
  • 「USACO08JAN」电话线Telephone Lines 解题报告

    题面

    大意:在加权无向图上求出一条从 (1) 号结点到 (N) 号结点的路径,使路径上第 (K + 1) 大的边权尽量小。

    思路:

    由于我们只能直接求最短路,不能记录过程中的具体的边——那样会特别麻烦

    所以,我们就尝试着去想更优的办法

    题目中所说,能够免去 (K) 条边的费用,那么对于要建设的边中,肯定免去费用最大 $K $ 条边更优

    我们关注的应该是第 (K+1) 大边的边权,因为其他边权大于这条边边权的边都会被略去

    这条边可以枚举吗?

    似乎不行,枚举的复杂度还要在最短路的基础上,乘上一个 (M) ,不就TLE(Time Limit Enough)了吗……

    那么——对于这个边的边权,能不能二分呢?

    首先,二分需要满足单调性

    题目中,这条第 (K+1) 大的边边权越小,能够满足的情况越少,反之亦然

    因此我们可以使用二分的方法来查找答案

    怎么判断满足或不满足

    对于边权大于 (mid) 的边,我们改变它的边权为1,否则为0,然后再跑最短路,这样得出来的结果应该是从 (1) 号结点到 $N $ 号结点至少要有几条大于 (mid) 的边,然后与 (K) 比较,小于 (K) 则满足,否则不满足

    Code:

    #include<bits/stdc++.h>
    #define INF 0x7f7f7f7f
    #define M 10010
    #define N 1010
    using namespace std;
    struct node{
    	int to,cost;
    	int nxt;
    	node(int a,int b):to(a),cost(b){	}
    	node(){	}
    }b[M<<1];
    int head[N],d[N],vis[N];
    int n,m,res,t,ans=INF;//初值一样要为INF
    int read()
    {
    	int s=0;
    	char c=getchar();
    	while(!isdigit(c))
    		c=getchar();
    	while(isdigit(c))
    	{
    		s=(s<<1)+(s<<3)+c-'0';
    		c=getchar();
    	}
    	return s;
    }
    void add(int x,int y,int cost)//建边,正反一起
    {
    	b[++t]=node(y,cost);
    	b[t].nxt=head[x];
    	head[x]=t;
    	b[++t]=node(x,cost);
    	b[t].nxt=head[y];
    	head[y]=t;
    	return;
    }
    bool BFS(int k)//好吧,这里不算严格的最短路,因为边权变成了0和1,可以直接宽搜搞定,但是下面的程序,
    {//明明是一个真SPFA,假宽搜
    	int i,to,cur,cost;
    	for(i=1;i<=n;i++)
    	{
    		d[i]=INF;
    		vis[i]=0;
    	}
    	queue<int>p;
    	p.push(1);
    	vis[1]=1;
    	d[1]=0;
    	while(!p.empty())
    	{
    		cur=p.front();p.pop();
    		vis[cur]=0;
    		for(i=head[cur];i;i=b[i].nxt)
    		{
    			to=b[i].to;
    			cost=d[cur]+(b[i].cost>k);//处理边权
    			if(cost<d[to])
    			{
    				d[to]=cost;
    				if(!vis[to])
    				{
    					vis[to]=1;
    					p.push(to);
    				}
    			}
    		}
    	}
    	if(d[n]<=res)//判断
    		return 1;
    	return 0;
    }
    int main()
    {
    	int i;
    	int x,y,cost;
    	int l,r,mid;
    	n=read();m=read();res=read();
    	l=r=0;
    	for(i=1;i<=m;i++)
    	{
    		x=read();y=read();cost=read();
    		add(x,y,cost);//建边,注意是双向的
    		r=max(r,cost);//r的上限,可以自己赋为1e6,这是题目中给的最大值
    	}
    	while(l<=r)
    	{
    		mid=(l+r)>>1;
    		if(BFS(mid))//判断
    		{
    			ans=mid;
    			r=mid-1;
    		}
    		else
    			l=mid+1;
    	}
    	if(ans==INF)//初值应该为INF,不能为0,因为有可能电信公司比较大方,免费之类的——给我多好
    		ans=-1;
    	printf("%d",ans);
    	return 0;
    }
    

    另外提供一个比较high的评测

    在洛谷过了,这里不一定过哦!

  • 相关阅读:
    Git之常用的命令操作
    Linux之创建777权限的文件
    Mysql union
    读取MySQL数据表字段信息
    Linux下mysql启动失败
    TP5之使用layui分页样式
    使用Bootstrap实现表格列的显示与隐藏
    MySQL之避免插入重复数据
    Linux命令之清空当前文件
    opensns入门
  • 原文地址:https://www.cnblogs.com/hovny/p/10237742.html
Copyright © 2011-2022 走看看