暑假集训--最短路

迪杰斯特拉(这次还跟dalao学了宏定义,感觉逼格提高了)

//二叉堆优化过的dij
#include <cmath>
#include <queue>
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define forn(i, n) for (int i = 0; i < (n); i++)
#define forab(i, a, b) for (int i = (a); i <= (b); i++)
#define forba(i, b, a) for (int i = (b); i >= (a); i--)
#define mset(a, n) memset(a, n, sizeof(a))
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define P pair<int,int>
#define fi first
#define se second
using namespace std;
#define N 1000010
#define maxn 1005
#define inf 0x3f3f3f3f
#define ll long long
int head[N], ver[N], edge[N], Next[N], d[N];
int n, m, tot;
bool vis[N];
priority_queue<pair<int,int> > q;  //first存的d[i]的相反数,这样就变成了小根堆 
void addedge(int x,int y,int z)
{
    ver[++tot] = y;
    edge[tot] = z;
    Next[tot] = head[x];
    head[x] = tot;
}
void Init()
{
	mset(head,0);
	tot=0;
}
void dij()
{
	mset(d,0x3f);
	mset(vis,0);
    d[1] = 0; //以1 为起始点,
    q.push(make_pair(0, 1));
    while(q.size()) 
	{
        int x = q.top().se;
        q.pop();
        if(vis[x])
            continue;
        vis[x] = 1;
        for (int i = head[x]; i;i=Next[i])
        {
            int y = ver[i];
            int z = edge[i];
            if(d[y]>d[x]+z)
            {
                d[y] = d[x] + z; //更新
                q.push(make_pair(-d[y], y));
            }
        }
    }
}
int main()
{
    fast;
    cin >> n >> m;
    forab(i,1,m)
    {
        int x, y, z;
        cin >> x >> y >> z;
        addedge(x, y, z);
        //addedge(y,x,z);  //无向边
    }
    dij();
    forab(i, 1, n) cout << d[i] << endl;  //单源最短路
    system("pause");
}

SPFA(有负权边也可用)

#include <cmath>
#include <queue>
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define forn(i, n) for (int i = 0; i < (n); i++)
#define forab(i, a, b) for (int i = (a); i <= (b); i++)
#define forba(i, b, a) for (int i = (b); i >= (a); i--)
#define mset(a, n) memset(a, n, sizeof(a))
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define P pair<int,int>
#define fi first
#define se second
using namespace std;
#define N 1000010
#define maxn 1005
#define inf 0x3f3f3f3f
#define ll long long
int head[N], ver[N], edge[N], Next[N], d[N];
int n, m, tot;
bool vis[N];
int in[N];  //判负环可用
void addedge(int x,int y,int z)
{
    ver[++tot] = y;
    edge[tot] = z;
    Next[tot] = head[x];
    head[x] = tot;
}
void Init()
{
	mset(head,0);
	tot=0;
}
void spfa()
{
    mset(d, 0x3f);
    mset(vis, 0);   //这里的vis跟dij的有所不同,spfa的vis是记录点是否在队列里面,所以要每次进出更新
    d[1] = 0;
    vis[1] = 1;
    q.push(1);
    while(q.size())
    {
        int x = q.front();
        q.pop();
        vis[x] = 0;  //x出队列
        for (int i = head[x]; i;i=Next[i])
        {
            int y = ver[i];
            int z = edge[i];
            if(d[y]>d[x]+z)
            {
                d[y] = d[x] + z;
                if(!vis[y])
                {
                    vis[y] = 1;
                    q.push(y);
                }
            }
        }
    }
}
int main()
{
    fast;
    cin >> n >> m;
    forab(i,1,m)
    {
        int x, y, z;
        cin >> x >> y >> z;
        addedge(x, y, z);
        //addedge(y, x, z);  无向边
    }
    spfa();
    forab(i, 1, n) cout << d[i] << endl;
}

spfa也可以用priority_queue优化,这里就不贴代码了(

负环和差分约束

之前写程序设计作业的时候就了解过spfa和差分约束,这里再解释一下

负环: 一个边权和为复数的环称为负环。
不难知道,如果图中存在负环,那么无论经过多少次迭代,总存在有向边(x,y,z)使得
dist[y] > dist[x] + z则spfa算法无法结束。

根据抽屉原理(不懂自行百度,我记着小学奥数就讲过= =),若存在一个dist[x] 从起点1到节点x的最短路包含>=n条边,则这条路径必然重复经过的某个结点p,也就是说这条最短路上存在一个环,环上的每个点都能更新下一个点的dist,p绕环一圈最后可以更新他自己,因此,整个环的总长度为负数,每绕一圈总长度就会减少一点,越来越少,不可能收敛到每条边都满足三角不等式的状态。

因此 有以下方法判定法则(有了spfa就不用bellman-ford了吧,我是只看了spfa)

第一种 按照上段文章所写,设cnt[x] 表示从1到x的最短路径包含的边数,cnt[1] = 0,当执行dist[y] = dist[x] + z 时,同样更新cnt[y] = cnt[x] + 1,此时若有cnt[y] >=n 则存在负环,若正常结束算法,则没有负环

第二种 记录每个点的入队次数 次数达到n时则有负环,不过一般不如第一种的效率高。

差分约束 另一篇文章里面给过一些详细的证明这里就不写了。

贴几道当时花了一些时间或者犯了一些zz错误的题

E - Currency Exchange

Several currency exchange points are working in our city. Let us suppose that each point specializes in two particular currencies and performs exchange operations only with these currencies. There can be several points specializing in the same pair of currencies. Each point has its own exchange rates, exchange rate of A to B is the quantity of B you get for 1A. Also each exchange point has some commission, the sum you have to pay for your exchange operation. Commission is always collected in source currency.
For example, if you want to exchange 100 US Dollars into Russian Rubles at the exchange point, where the exchange rate is 29.75, and the commission is 0.39 you will get (100 - 0.39) * 29.75 = 2963.3975RUR.
You surely know that there are N different currencies you can deal with in our city. Let us assign unique integer number from 1 to N to each currency. Then each exchange point can be described with 6 numbers: integer A and B - numbers of currencies it exchanges, and real R AB, C AB, R BA and C BA - exchange rates and commissions when exchanging A to B and B to A respectively.
Nick has some money in currency S and wonders if he can somehow, after some exchange operations, increase his capital. Of course, he wants to have his money in currency S in the end. Help him to answer this difficult question. Nick must always have non-negative sum of money while making his operations.
Input
The first line of the input contains four numbers: N - the number of currencies, M - the number of exchange points, S - the number of currency Nick has and V - the quantity of currency units he has. The following M lines contain 6 numbers each - the description of the corresponding exchange point - in specified above order. Numbers are separated by one or more spaces. 1<=S<=N<=100, 1<=M<=100, V is real number, 0<=V<=10 3.
For each point exchange rates and commissions are real, given with at most two digits after the decimal point, 10 -2<=rate<=10 2, 0<=commission<=10 2.
Let us call some sequence of the exchange operations simple if no exchange point is used more than once in this sequence. You may assume that ratio of the numeric values of the sums at the end and at the beginning of any simple sequence of the exchange operations will be less than 10 4.
Output
If Nick can increase his wealth, output YES, in other case output NO to the output file.
Sample Input
3 2 1 20.0
1 2 1.00 1.00 1.00 1.00
2 3 1.10 1.00 1.10 1.00
Sample Output
YES

题目大意就是首先给你一个不同种货币之间的兑换公式,之后给了你一些货币的基本信息,和你一开始拥有的货币种类和数量,问能否经过一系列的兑换,再次回到原有的货币种类,可以使价值提高

加粗这句话很显然的告诉了我们这道题是判断图中是否存在以原有货币为起点的正环,按照spfa判负环的套路改一下就可以了。

#include <cstdio>
#include <queue>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1005
double d[N], cost[N][N], rate[N][N];
bool vis[N];
int n, m, s;
double v;
queue<int> q;
int spfa(int s)
{
    memset(vis, 0, sizeof(vis));
    memset(d, 0, sizeof(d));
    d[s] = v;
    vis[s] = 1;
    q.push(s);
    while(q.size())
    {
        int x = q.front();
        q.pop();
        vis[x] = 0;
        for (int i = 1; i <= n;i++)
        {
            if(d[i]<(d[x]-cost[x][i])*rate[x][i])
            {
                d[i] = (d[x] - cost[x][i]) * rate[x][i];
                if(d[s]>v)
                {
                    return true;
                }
                if(!vis[i])
                {
                    q.push(i);
                    vis[i] = 1;
                }
            }
        }
    }
    return false;
}
int main()
{
    scanf("%d%d%d%lf", &n, &m, &s, &v);
    for (int i = 1; i <= n;i++)
        for (int j = 1; j <= n;j++)
        {
            if(i==j)
                rate[i][j] = 1;
            else
                rate[i][j] = 0;
            cost[i][j] = 0;
        }
    for (int i = 1; i <= m; i++)
    {
        int a, b;
        double rab, rba, cab, cba;
        scanf("%d%d%lf%lf%lf%lf", &a, &b, &rab, &cab, &rba, &cba);
        cost[a][b] = cab;
        cost[b][a] = cba;
        rate[a][b] = rab;
        rate[b][a] = rba;
    }
    if(spfa(s))
        printf("YES\n");
    else
        printf("NO\n");
}

F - Wormholes

While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ’s farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1…N, M (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.

As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself ? .

To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.

Input
Line 1: A single integer, F. F farm descriptions follow.
Line 1 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2… M+1 of each farm: Three space-separated numbers ( S, E, T) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path.
Lines M+2… M+ W+1 of each farm: Three space-separated numbers ( S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.
Output
Lines 1… F: For each farm, output “YES” if FJ can achieve his goal, otherwise output “NO” (do not include the quotes).
Sample Input
2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8
Sample Output
NO
YES

其实就是一道spfa判断负环的很板子的题,这里我采用了上述第二种方法

#include <cstdio>
#include <queue>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1000010
int head[N], ver[N], edge[N], Next[N], d[N];
int f, n, m, w, tot;
bool vis[N];
int in[N];
queue<int> q;
void addedge(int x,int y,int z)
{
    ver[++tot] = y;
    edge[tot] = z;
    Next[tot] = head[x];
    head[x] = tot;
}
int spfa()
{
    memset(d, 0x3f, sizeof(d));
    memset(vis, 0, sizeof(vis));
    memset(in, 0, sizeof(in));
    d[1] = 0;
    vis[1] = 1;
    q.push(1);
    in[1]++;
    while(q.size())
    {
        int x = q.front();
        q.pop();
        vis[x] = 0;
        for (int i = head[x]; i;i=Next[i])
        {
            int y = ver[i];
            int z = edge[i];
            if(d[y]>d[x]+z)
            {
                d[y] = d[x] + z;
                if(!vis[y])
                {
                    vis[y] = 1;
                    q.push(y);
                    in[y]++;
                    if(in[y]>=n)
                        return true;
                }
            }
        }
    }
    return false;
}
int main()
{
    scanf("%d", &f);
    while(f--)
    {
        scanf("%d%d%d", &n, &m, &w);
        tot = 0;
        memset(head, 0, sizeof(head));
        for (int i = 1; i <= m;i++)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            addedge(x, y, z);
            addedge(y, x, z);
        }
        for (int i = 1; i <= w;i++)
        {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);  //回到z秒之前,所以为负权边
            addedge(x, y, -z);
        }
        if(spfa())
            printf("YES\n");
        else
            printf("NO\n");
    }
}

G - MPI Maelstrom

给定一个下三角矩阵,询问从1开始到其他点的最短路径中,最长的那个是多少

题目太长这里就不贴原题描述了,

Sample Input
5
50
30 5
100 20 50
10 x x 10
Sample Output
35

有点不一样的也就是x代表不连通,将其权值赋为inf就好了

#include <cstdio>
#include <string>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define N 110
#define inf 0x3f3f3f3f
int Map[N][N], d[N];
bool vis[N];
int n;
priority_queue<pair<int, int> > q;
void dij()
{
    memset(vis, 0, sizeof(vis));
    for (int i = 1; i <= n;i++)
        d[i] = Map[1][i];
    q.push(make_pair(0, 1));
    while(q.size())
    {
        int x = q.top().second;
        q.pop();
        if(vis[x])
            continue;
        vis[x] = 1;
        for (int i = 1; i <= n;i++)
        {
            if(d[i]>=d[x]+Map[x][i]&&!vis[i])
            {
                d[i] = d[x] + Map[x][i];
                q.push(make_pair(-d[i], i));
            }
        }
    }
}
int cal(string s)
{
    int a = 0;
    int len = s.length();
    //printf("len=%d\n", len);
    for (int i = 0; i < len;i++)
    {
        a += ((int)(s[i] - '0')*pow(10, len - i - 1));
    }
    return a;
}
int main()
{
    scanf("%d", &n);
    getchar();
    for (int i = 1; i <= n;i++)
        Map[i][i] = 0;
    string s;
    for (int i = 2; i <= n;i++)
    {
        for (int j = 1; j < i;j++)
        {
            cin >> s;
            if(s[0]=='x')
                Map[i][j] = Map[j][i] = inf;
            else
                Map[i][j] = Map[j][i] = cal(s);
        }
    }
    /*for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n;j++)
        {
            cout << Map[i][j] << ' ';
        }
        cout << endl;
    }*/
    dij();
    int ans = -1;
    for (int i = 1; i <= n;i++)
    {
        //printf("%d ", d[i]);
        ans = max(ans, d[i]);
    }
    printf("%d\n", ans);
}
/*
5
50
30 5
100 20 50
10 x x 10
 */

H - Cow Contest

N (1 ≤ N ≤ 100) cows, conveniently numbered 1…N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors.

The contest is conducted in several head-to-head rounds, each between two cows. If cow A has a greater skill level than cow B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B), then cow A will always beat cow B.

Farmer John is trying to rank the cows by skill level. Given a list the results of M (1 ≤ M ≤ 4,500) two-cow rounds, determine the number of cows whose ranks can be precisely determined from the results. It is guaranteed that the results of the rounds will not be contradictory.

Input

  • Line 1: Two space-separated integers: N and M
  • Lines 2…M+1: Each line contains two space-separated integers that describe the competitors and results (the first integer, A, is the winner) of a single round of competition: A and B

Output

  • Line 1: A single integer representing the number of cows whose ranks can be determined

Sample Input
5 5
4 3
4 2
3 2
1 2
2 5
Sample Output
2

n头牛m场比赛
每场比赛两头牛,第一头为胜者,问经过m轮比赛之后最多能确定几头牛的名次。
因为这题数据范围不算大,可以说挺小的,我就采用了简单易懂比较粗暴的方法(**其实就是自己太菜了想不出别的 **

关于建图(这题为啥用图论做我就不用说了吧!) a击败了b 从a到b建一条有向边,
假设在之后某次比赛中 c击败了a 则c到a建一条有向边 c到b也要建一条有向边.
根据这个建图方式我们可以得出:如果某头牛也就是某个结点的出度+入度=n-1 则他的排名就可以被确定

#include <cstdio>
#include <string>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define N 110
#define inf 0x3f3f3f3f
int Map[N][N];
int n, m;
void Find(int x,int y)
{
    for (int i = 1; i <= n;i++)
    {
        if(Map[i][x]==1)
            Map[i][y] = 1; // i能击败x,必定能击败y
    }
}
int Cnt()
{
    int ans = 0;
    for (int i = 1; i <= n;i++)
    {
        int cnt = 0;
        for (int j = 1; j <= n;j++)
        {
            if(Map[i][j]==1)
                cnt++;
            if(Map[j][i]==1)
                cnt++;
        }
        if(cnt==n-1)
            ans++;
    }
    return ans;
}
int main()
{
    scanf("%d%d", &n, &m);
    memset(Map, 0x3f, sizeof(Map));
    for (int i = 1; i <= n;i++)
        Map[i][i] = 0;
    for (int i = 1; i <= m; i++)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        Map[x][y] = 1; //x->y连通
    }
    for (int i = 1; i <= n;i++)
    {
        for (int j = 1; j <= n;j++)
        {
            if(Map[i][j]==1)
                Find(i, j);
        }
    }
        /*for (int i = 1; i <= n;i++)
    {
        for (int j = 1; j <= n;j++)
        {
            printf("%d ", Map[i][j]);
        }
        puts("");
    }
    puts("");*/
    printf("%d\n", Cnt());
}
/*
5 5
4 3
4 2
3 2
1 2
2 5

4 3
1 4
1 2
2 3

4 4
1 4
1 2
2 3
4 2

 */

K - Candies

During the kindergarten days, flymouse was the monitor of his class. Occasionally the head-teacher brought the kids of flymouse’s class a large bag of candies and had flymouse distribute them. All the kids loved candies very much and often compared the numbers of candies they got with others. A kid A could had the idea that though it might be the case that another kid B was better than him in some aspect and therefore had a reason for deserving more candies than he did, he should never get a certain number of candies fewer than B did no matter how many candies he actually got, otherwise he would feel dissatisfied and go to the head-teacher to complain about flymouse’s biased distribution.

snoopy shared class with flymouse at that time. flymouse always compared the number of his candies with that of snoopy’s. He wanted to make the difference between the numbers as large as possible while keeping every kid satisfied. Now he had just got another bag of candies from the head-teacher, what was the largest difference he could make out of it?

Input
The input contains a single test cases. The test cases starts with a line with two integers N and M not exceeding 30 000 and 150 000 respectively. N is the number of kids in the class and the kids were numbered 1 through N. snoopy and flymouse were always numbered 1 and N. Then follow M lines each holding three integers A, B and c in order, meaning that kid A believed that kid B should never get over c candies more than he did.

Output
Output one line with only the largest difference desired. The difference is guaranteed to be finite.

Sample Input
2 2
1 2 5
2 1 4
Sample Output
5

给n个人派糖果,给出m组数据,每组数据包含A,B,C 三个数,
意思是A的糖果数比B少的个数不多于c,即B的糖果数 - A的糖果数<= C 。
最后求n 比 1 最多多多少糖果。

差分约束! 如果还有不明白差分约束的可以去看我的另一篇博客,里面有写,

B的糖果数 - A的糖果数<= C 即为从A到B建一条权值为C的有向边
之后用spfa跑最短路即可,如果图中有负环则该系统无解(这题好像不用考虑)
如果顺利结束则 Xi = dist[i] 就为该系统的一组解(蓝书原话)
这里用了二叉堆优化过的spfa 用queue 的话好像会T掉

#include <cstdio>
#include <string>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define N 1000005
#define ll long long
#define inf 0x3f3f3f3f
int head[N], edge[N], ver[N], Next[N], d[N];
bool vis[N];
int n, tot, m;
void addedge(int x,int y,int z)
{
    ver[++tot] = y;
    edge[tot] = z;
    Next[tot] = head[x];
    head[x] = tot;
}
priority_queue<pair<int, int> > q;
void spfa()
{
    memset(d, 0x3f, sizeof(d));
    memset(vis, 0, sizeof(vis));
    d[1] = 0;
    q.push(make_pair(0,1));
    while(q.size())
    {
        int x = q.top().second;
        q.pop();
        if(vis[x])
            continue;
        vis[x] = 1;
        for (int i = head[x]; i;i=Next[i])
        {
            int y = ver[i];
            int z = edge[i];
            if(d[y]>d[x]+z)
            {
                d[y]=d[x] + z;
                q.push(make_pair(-d[y], y));
            }
        }
    }
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m;i++)
    {
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        addedge(x, y, z);
    }
    spfa();
    printf("%d\n", d[n]);
}

L - Subway

小k要从家去学校,他可以选择步行或者地铁,步行的速度是10km/h,地铁的速度是40km/h。假设小k非常的幸运,每次他到地铁站就立刻会有地铁。小k可以随意上下地铁,并且可以在地铁线路之间转换。所有的地铁运行都是双向的。

Input
输入第一行包括家和学校的x,y坐标,接下来是若干条地铁线。
每条地铁线包括站点的x,y坐标,有序排列,假设地铁在相邻的两站之间直线运行,每条地铁线至少有两个站,地铁线的描述以-1,-1结束。
该市最多有200个地铁站。

Output
输出是上学所需的时间,四舍五入到最近的分钟,采取最快的路线。

Sample Input
0 0 10000 1000
0 200 5000 200 7000 200 -1 -1
2000 600 5000 600 10000 600 -1 -1
Sample Output
21

md这题写了我一上午,最后发现是公式写错了 时间 = 路程 * 速度 (逃

这题稍微麻烦的地方就是 建图确实有很多需要考虑的点,同一条线相邻的地铁站可以在读入的同时就把边建好,之后再在任两点之间建边,最后跑最短路即可

细节方面建议自己亲自写一写,有可能就会发现一些问题

#include <cmath>
#include <queue>
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define forn(i, n) for (int i = 0; i < (n); i++)
#define forab(i, a, b) for (int i = (a); i <= (b); i++)
#define forba(i, b, a) for (int i = (b); i >= (a); i--)
#define mset(a, n) memset(a, n, sizeof(a))
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define P pair<int,int>
using namespace std;
#define N 1000010
#define maxn 1005
#define ll long long
int head[N], ver[N], Next[N];
int tot;
double edge[N], d[N];
bool vis[N], jud[maxn][maxn];
priority_queue<pair<int, int> > q;
struct node
{
    int x, y;
} po[N];
void addedge(int x,int y,double z)
{
    ver[++tot] = y;
    edge[tot] = z;
    Next[tot] = head[x];
    head[x] = tot;
}
double dis(node a,node b)
{
    return sqrt(1.0*(a.x - b.x) * (a.x - b.x) + 1.0*(a.y - b.y) * (a.y - b.y));
}
void dij()
{
    memset(d, 0x7f, sizeof(d));
    memset(vis, 0, sizeof(vis));
    d[1] = 0;
    q.push(make_pair(0, 1));
    while(q.size())
    {
        int x = q.top().second;
        q.pop();
        if(vis[x])
            continue;
        vis[x] = 1;
        for (int i = head[x]; i;i=Next[i])
        {
            int y = ver[i];
            double z = edge[i];
            if(d[y]>d[x]+z)
            {
                d[y] = d[x] + z;
                q.push(make_pair(-d[y], y));
            }
        }
    }
}

int main()
{
    fast;
    scanf("%d%d%d%d", &po[1].x, &po[1].y, &po[2].x, &po[2].y);
    //cin >> po[1].x >> po[1].y >> po[2].x >> po[2].y;
    int cnt = 3;
    int x, y;
    while(~scanf("%d%d",&x,&y))
    {
        po[cnt].x = x;
        po[cnt++].y = y;
        while(~scanf("%d%d",&x,&y))
        {
            if(x==-1&&y==-1)
            {
                po[cnt].x = x;
                po[cnt++].y = y;
                break;
            }
            po[cnt].x = x;
            po[cnt++].y = y;
            addedge(cnt - 1, cnt - 2, dis(po[cnt - 1], po[cnt - 2]) * 3.0 / 2000);
            addedge(cnt - 2, cnt - 1, dis(po[cnt - 1], po[cnt - 2]) * 3.0 / 2000);
            jud[cnt - 1][cnt - 2] = jud[cnt - 2][cnt - 1] = 1;
        }
    }
    cnt--;
    forab(i,1,cnt-1)
    {
        forab(j,1,cnt-1)
        {
            if(po[i].x==-1||po[j].x==-1)
                continue;
            if(!jud[i][j])
            {
                addedge(i, j, dis(po[i], po[j]) * 3 * 1.0 / 500);   //其他点之间建边
                addedge(j, i, dis(po[i], po[j]) * 3 * 1.0 / 500);
                jud[i][j] = jud[j][i] = 1;
            }
        }
    }
    dij();
    int a = (int)d[2];
    int b = (int)(d[2] * 10 - a * 10);
    if(b>=5)
        a++;
    printf("%d\n", a);
}
/*
0 0 10000 1000
0 200 5000 200 7000 200 -1 -1 
2000 600 5000 600 10000 600 -1 -1
 */

S - Layout

Like everyone else, cows like to stand close to their friends when queuing for feed. FJ has N (2 <= N <= 1,000) cows numbered 1…N standing along a straight line waiting for feed. The cows are standing in the same order as they are numbered, and since they can be rather pushy, it is possible that two or more cows can line up at exactly the same location (that is, if we think of each cow as being located at some coordinate on a number line, then it is possible for two or more cows to share the same coordinate).

Some cows like each other and want to be within a certain distance of each other in line. Some really dislike each other and want to be separated by at least a certain distance. A list of ML (1 <= ML <= 10,000) constraints describes which cows like each other and the maximum distance by which they may be separated; a subsequent list of MD constraints (1 <= MD <= 10,000) tells which cows dislike each other and the minimum distance by which they must be separated.

Your job is to compute, if possible, the maximum possible distance between cow 1 and cow N that satisfies the distance constraints.
Input
Line 1: Three space-separated integers: N, ML, and MD.

Lines 2…ML+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at most D (1 <= D <= 1,000,000) apart.

Lines ML+2…ML+MD+1: Each line contains three space-separated positive integers: A, B, and D, with 1 <= A < B <= N. Cows A and B must be at least D (1 <= D <= 1,000,000) apart.
Output
Line 1: A single integer. If no line-up is possible, output -1. If cows 1 and N can be arbitrarily far apart, output -2. Otherwise output the greatest possible distance between cows 1 and N.
Sample Input
4 2 1
1 3 10
2 4 20
2 3 3
Sample Output
27

还是一道典型的差分约束的题目,不过给了一些最大距离和最小距离,将最小距离的不等式变换方向就变成了最大距离,一样spfa跑一边即可,如果d[n] = inf 则输出-2 如果有负环则输出-1

#include
#include
#include
#include
#include
#include
#include
#define forn(i, n) for (int i = 0; i < (n); i++)
#define forab(i, a, b) for (int i = (a); i <= (b); i++)
#define forba(i, b, a) for (int i = (b); i >= (a); i–)
#define mset(a, n) memset(a, n, sizeof(a))
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define P pair<int,int>
using namespace std;
#define N 1000010
#define inf 0x3f3f3f3f

int head[N], ver[N], Next[N], edge[N], d[N];
int n, ml, md, tot;
bool vis[N];
int in[N];

void addedge(int x,int y,int z)
{
ver[++tot] = y;
edge[tot] = z;
Next[tot] = head[x];
head[x] = tot;
}

void spfa()
{
mset(d, 0x3f);
mset(vis, 0);
queue q;
d[1] = 0;
vis[1] = 1;
in[1]++;
q.push(1);
while(q.size())
{
int x = q.front();
q.pop();
vis[x] = 0;
for (int i = head[x]; i;i=Next[i])
{
int y = ver[i];
int z = edge[i];
if(d[y]>d[x]+z)
{
d[y] = d[x] + z;
if(!vis[y])
{
in[y]++;
if(in[y]>=n)
{
puts("-1");
return;
}
vis[y] = 1;
q.push(y);
}
}
}
}
if(d[n]==inf)
puts("-2");
else
cout << d[n] << endl;
}

int main()
{
fast;
cin >> n >> ml >> md;
forab(i,1,ml)
{
int x, y, z;
cin >> x >> y >> z;
addedge(x, y, z);
//addedge(y, x, z);
}
forab(i,1,md)
{
int x, y, z;
cin >> x >> y >> z;
addedge(y, x, -z);
//addedge(y, x, -z);
}
spfa();
}
/*
4 2 1
1 3 10
2 4 20
2 3 3
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值