Holy Grail(2019 ACM-ICPC 南京赛区网络赛 H)

Problem Description

As the current heir of a wizarding family with a long history,unfortunately, you find yourself forced to participate in the cruel Holy Grail War which has a reincarnation of sixty years.However,fortunately,you summoned a Caster Servant with a powerful Noble Phantasm.When your servant launch her Noble Phantasm,it will construct a magic field,which is actually a directed graph consisting of n vertices and m edges.More specifically,the graph satisfies the following restrictions :

  • Does not have multiple edges(for each pair of vertices x and y, there is at most one edge between this pair of vertices in the graph) and does not have self-loops(edges connecting the vertex with itself).
  • May have negative-weighted edges.
  • Does not have a negative-weighted loop.
  • n<=300 , m<=500.

Currently,as your servant's Master,as long as you add extra 6 edges to the graph,you will beat the other 6 masters to win the Holy Grail.

However,you are subject to the following restrictions when you add the edges to the graph:

  • Each time you add an edge whose cost is c,it will cost you c units of Magic Value.Therefore,you need to add an edge which has the lowest weight(it's probably that you need to add an edge which has a negative weight).
  • Each time you add an edge to the graph,the graph must not have negative loops,otherwise you will be engulfed by the Holy Grail you summon.

Input

Input data contains multiple test cases. The first line of input contains integer t — the number of testcases (1≤t≤5).

For each test case,the first line contains two integers n,m,the number of vertices in the graph, the initial number of edges in the graph.

Then m lines follow, each line contains three integers x, y and w (0≤x,y<n,-10^9−109≤w≤10^9109, x≠ y) denoting an edge from vertices x to y (0-indexed) of weight w.

Then 6 lines follow, each line contains two integers s,t denoting the starting vertex and the ending vertex of the edge you need to add to the graph.

It is guaranteed that there is not an edge starting from s to t before you add any edges and there must exists such an edge which has the lowest weight and satisfies the above restrictions, meaning the solution absolutely exists for each query.

Output

For each test case,output 6 lines.

Each line contains the weight of the edge you add to the graph.

Sample Input

1
10 15
4 7 10
7 6 3
5 3 3
1 4 11
0 6 20
9 8 25
3 0 9
1 2 15
9 0 27
5 2 0
7 3 -5
1 7 21
5 0 1
9 3 16
1 8 4
4 1
0 3
6 9
2 1
8 7
0 4

​​​​​​​Sample ​​​​​​​Output

-11
-9
-45
-15
17
7

题意:t 组样例,每组给出 n 个点 m 条边的 DAG 图,图中存在负权边,然后再依次给出 6 组查询 (x,y),要求在点 x 到点 y 间添加一条有向边,使得添加的边权最小,且保证添加边后图中没有负环

思路:

问题关键在于 6 次查询,每次查询完后所添的边仍在图中,下一次查询在上一次添完的基础上进行查询

根据题意,由于要使得添加的边权最小,我们只需要找出从 y 到 x 的最短路,然后取这个最短路的负值,使得从 x 到 y 构成一个边权为 0 的环,这样就能使得边权最小

加上图中存在负权边,因此跑 6 次 Bellman-Ford,每次跑完后添加新边,下一次再上一次填完的基础上继续进行即可

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL_INF 0x3f3f3f3f3f3f3f3f
#define LL long long
#define Pair pair<int,int>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL quickModPow(LL a,LL b,LL mod){ LL res=1; a=a%mod; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1;} return res; }
LL getInv(LL a,LL mod){ return quickModPow(a,mod-2,mod); }
const double EPS = 1E-10;
const int MOD = 1E9+7;
const int N = 500+5;
const int dx[] = {-1,1,0,0,-1,-1,1,1};
const int dy[] = {0,0,-1,1,-1,1,-1,1};
using namespace std;

struct Edge{
    int from,to;
    LL dis;
    Edge(){}
    Edge(int from,int to,LL dis):from(from),to(to),dis(dis){}
};
struct BellmanFord {
    int n,m;
    vector<Edge> edge;
    vector<int> G[N];
    bool vis[N];
    LL dis[N];

    void init(int n) {
        this->n=n;
        this->m=0;
        for(int i=0; i<n; i++)
            G[i].clear();
        edge.clear();
    }

    void addEdge(int from,int to,LL dis) {
        edge.push_back(Edge(from,to,dis));
        G[from].push_back(m++);
    }

    void negativeCycle(int S) {
        memset(vis,0,sizeof(vis));
        queue<int> Q;
        for(int i=0; i<n; i++)
            dis[i]=LL_INF;
        dis[S]=0;
        Q.push(S);

        while(!Q.empty()) {
            int x=Q.front();
            Q.pop();
            vis[x]=false;
            for(int i=0; i<G[x].size(); i++) {
                Edge &e=edge[G[x][i]];
                if(dis[e.to]> dis[x]+e.dis) {
                    dis[e.to] = dis[x]+e.dis;
                    if(!vis[e.to]) {
                        vis[e.to]=true;
                        Q.push(e.to);
                    }
                }
            }
        }
    }
} BF;

int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        int n,m;
        scanf("%d%d",&n,&m);
        BF.init(n+1);
        while(m--) { //普通边
            int x,y;
            LL dis;
            scanf("%d%d%lld",&x,&y,&dis);
            x++;
            y++;
            BF.addEdge(x,y,dis);
        }

        for(int i=1;i<=6;i++){//6次Ford
            int x,y;
            scanf("%d%d",&x,&y);
            x++;
            y++;
            BF.negativeCycle(y);
            LL res=-BF.dis[x];//记录最小边权
            BF.addEdge(x,y,res);//建立新边
            printf("%lld\n",res);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值