POJ 3159 Candies 差分入门

6 篇文章 0 订阅
5 篇文章 0 订阅

Candies
Time Limit: 1500MS Memory Limit: 131072K
Total Submissions: 31673 Accepted: 8831
Description

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

感觉这算差分绝对的入门题了吧。

关于差分约束系统:

转载一个博客:
大佬关于差分约束的博

下面就是自己的整理:
差分约束系统就是给出一些形如x-y<=b不等式的约束,询问:
1.求最大解,2.求最小解,3.是否有满足问题的解。
对不等式:
x[v]-x[u]<=a;
经过一系列变形:
x[u]-x[v]>=-a
x[u]>=x[v]+(-a);
到这一步就很容易发现这个形式和求最短路的松弛操作非常像:

if(dis[v]>dis[u]+edge[i].w)
    dis[v]=dis[u]+edge[i].w;

所以我们就可以从u到v连一条边权为a的有向边(从v到u连一条边权为-a的有向边)然后求x[n]-x[1]的最大值就可以转化为求1到n的最短路。
如果是将上式中的不等号反向:
x[v]-x[u]>=a 最后求x[n]-x[1]最小解,则是求1到n的最长路。
(用三角不等式会更好理解)

关于判断解的存在性:
1。如果生成的图中出现了负权圈则无解。
判断负环:
SPFA 如果一个点入队次数> n,则证明存在负环。
2.如果无法到达,则有无数组解。
对于无法到达的情况的处理:加一个超级源点S,从S到任意的顶点边权为0,然后从该点出发。
3.有解 参照上面,

关于既有>=、<=
这两个不等号无疑是很容易转换的,所以我们可以根据所求的来判断怎么转换:
如果求最大解 则转化为<= 求最短路
如果求最小解 则转化为>= 求最长路

关于存在>、<的情况
如果输入的值都为整数,则可以根据整数的性质来转化:
eg:a< b 则a<=b-1

接下来终于是这道题了23333
题意:(题意也是去偷的。。。)
给n个人发糖果,给出m组限制,每组限制包含A,B,c 三个数,
满足B的糖果数 - A的糖果数<= c 。
最后求n 比 1 最多多多少糖果。

这很容易看出是一道差分的题,完美满足各种条件。。
x[b]-x[a]<=c
则可以从a向b连一条权值为c的边,最后跑一遍最短路就行了。
//朴素的spfa比较快

#include<cstdio>
#include<cstring>
#include<stack>
#define xxx pair<int,int>
#include<queue>
using namespace std;

const int N = 150000 + 10;
const int M = 30000 + 10;

int n,m;
//priority_queue<int,vector<int>,greater<int> >q;
priority_queue<xxx,vector<xxx>,greater<xxx> >q;

struct node{
    int pre,v,w;
}edge[N];

int num=0;
int head[N];

void addedge(int from,int to,int w){
    num++;
    edge[num].pre=head[from];
    edge[num].v=to;
    edge[num].w=w;
    head[from]=num;
}

int dis[N];
bool vis[N];

void DI(){
    memset(dis,127,sizeof(dis));
    memset(vis,0,sizeof(vis));
    q.push(make_pair(0,1)),dis[1]=0;
    while(!q.empty()){
        int u=q.top().second;
        q.pop();
        if(vis[u]) continue;
        vis[u]=1;
        for(int i=head[u];i;i=edge[i].pre){
            int v=edge[i].v;
            if(dis[v]>dis[u]+edge[i].w){
                dis[v]=dis[u]+edge[i].w;
                q.push(make_pair(dis[v],v));
            }
        }
    }
}

stack <int> s;

void SPFA(){
    memset(dis,127,sizeof(dis));
    memset(vis,0,sizeof(vis));
    s.push(1);dis[1]=0;
    while(!s.empty()){
        int u=s.top();s.pop();
        vis[u]=false;
        for(int i=head[u];i;i=edge[i].pre){
            int v=edge[i].v;
            if(dis[v]>dis[u]+edge[i].w){
                dis[v]=dis[u]+edge[i].w;
                if(!vis[v]){
                    s.push(v);
                    vis[v]=true;
                }
            }
        }
    }
}

int main(){
    scanf("%d%d",&n,&m);
    while(m--){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        addedge(u,v,w);
    }
    //DI();
    SPFA();
    printf("%d",dis[n]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值