zoukankan      html  css  js  c++  java
  • [CF715B] Complete The Graph

    前言

    多写写构造题是有好处的

    题目

    CF

    洛谷

    讲解

    我们首先考虑无解

    对于每条不确定的边,我们令它们的权值为(1)

    如果此时最短路的结果大于(L),无解

    等于(L)可直接输出

    现在我们考虑如何让最短路从一个比(L)小的值变为(L)

    我们记(L)与这个值的差为(ADD)

    我们要做的就是让(s)(t)的最短路增加(ADD)

    这样貌似不太好想,但是如果让所有点全部加上(ADD)呢?

    豁然开朗!

    我们直接在跑(dij)的时候

    对于每条可修改边增加权值,当然这个值是可以直接算出来的

    如果通过这样的操作都不是(L),输出(NO)

    代码

    int tot;
    int U[MAXM],V[MAXM],head[MAXN];
    LL W[MAXM];
    bool c[MAXM];
    struct edge
    {
    	int v,ID,nxt;
    }e[MAXM << 1];
    void Add_Edge(int x,int y,int ID)
    {
    	e[++tot].v = y;
    	e[tot].nxt = head[x];
    	e[tot].ID = ID;
    	head[x] = tot;
    }
    void Add_Double_Edge(int x,int y,int ID)
    {
    	Add_Edge(x,y,ID);
    	Add_Edge(y,x,ID);
    }
    
    LL dis[2][MAXN];
    struct node
    {
    	int x;
    	LL val;
    	node(){}
    	node(int x1,LL val1){
    		x = x1;
    		val = val1;
    	}
    	bool operator < (const node &px)const{
    		return val > px.val;
    	}
    };
    LL ADD;
    void dij(int x)
    {
    	for(int i = 0;i < n;++ i) dis[x][i] = INF;
    	priority_queue<node> q;
    	q.push(node(s,dis[x][s] = 0));
    	while(!q.empty())
    	{
    		node t = q.top(); q.pop();
    		if(t.val > dis[x][t.x]) continue;
    		for(int i = head[t.x]; i ;i = e[i].nxt)
    		{
    			if(!x && t.val + W[e[i].ID] < dis[x][e[i].v])
    				q.push(node(e[i].v,dis[x][e[i].v] = t.val + W[e[i].ID]));
    			if(x)
    			{
    				if(c[e[i].ID]) W[e[i].ID] += Max(0ll,ADD - (t.val + W[e[i].ID] - dis[0][e[i].v]));
    				if(t.val + W[e[i].ID] < dis[x][e[i].v]) q.push(node(e[i].v,dis[x][e[i].v] = t.val + W[e[i].ID]));
    			}
    		}
    	}
    }
    void NO()
    {
    	printf("NO");
    	exit(0);
    }
    void print()
    {
    	printf("YES
    ");
    	for(int i = 1;i <= m;++ i)
    	{
    		Put(U[i],' ');
    		Put(V[i],' ');
    		Put(W[i],'
    ');
    	}
    	exit(0);
    }
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	n = Read(); m = Read(); L = Read(); s = Read(); t = Read();
    	for(int i = 1;i <= m;++ i)
    	{
    		U[i] = Read();
    		V[i] = Read();
    		W[i] = Read();
    		if(!W[i]) c[i] = 1,W[i] = 1;
    		Add_Double_Edge(U[i],V[i],i);
    	}
    	dij(0);
    	if(dis[0][t] > L) NO();
    	else if(dis[0][t] == L) print();
    	ADD = L - dis[0][t];
    	dij(1);
    	if(dis[1][t] < L) NO();
    	print();
    	return 0;
    }
    
  • 相关阅读:
    java 基本数据类型的取值范围
    警惕自增的陷阱
    三元操作符的类型务必一致
    不要随便设置随机种子
    优先使用整形池
    IN、ANY、ALL与SOME
    第六章-序列:字符串、列表和元组 笔记
    第十二章-安全性
    第五章-数字 课后答案
    第十一章-约束、视图与事务
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14175669.html
Copyright © 2011-2022 走看看