解题报告——差分约束系统

以前打了一道差分约束的模板,现在在专题中做到了,发现都不会。。。

1.

You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn.
Write a program that:
> reads the number of intervals, their endpoints and integers c1, ..., cn from the standard input,
> computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i = 1, 2, ..., n,
> writes the answer to the standard output.

Input
The first line of the input contains an integer n (1 <= n <= 50 000) - the number of intervals. The following n lines describe the intervals. The i+1-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50 000 and 1 <= ci <= bi - ai + 1.

Process to the end of file

Output
The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i = 1, 2, ..., n.

Sample Input
5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output
6

这题有很多的约束条件,题目中给出的是每一个区间的约束条件

a【x】表示1到x一共放了几个,那根据题目的约束条件,我们可以得出:

在x - y 区间 必须放 z个

a[y] - a[x-1] >= z   ->  a[x -1] - a[y] <= -z  -> a[x-1] <= a[y] - z 这个对应的就是从 y到x-1建-z边权的边

但是, 要完全跑出这个差分约束系统的话, 还要加两个隐藏的限制条件:

i 到 i+1至少放0个,i 到 i+1 最多放1个:

a[i+1] - a[i] >= 0   --->   a[i] - a[i+1] <= 0        a[i+1] - a[i] <= 1 --->  a[i+1] <= a[i] + 1

差分约束除了搭建好约束条件以外, 还要注意边界搜索点的选择, 这题应该是选最小出现的一个数字,在它之前不必放了,所以把它当起点, 以最大的为终点, 因为比他大的不必放了。

#include<bits/stdc++.h>
using namespace std;
const int Maxn = 60000;
const int Emax = 160005;
int head[Maxn],cnt;
struct edge
{
    int v,w,next;
}e[Emax];
 
void addedge(int cu,int cv,int cw)
{
    cnt ++;
    e[cnt].v = cv;
    e[cnt].w = cw;
    e[cnt].next = head[cu];
    head[cu] = cnt;
}
 
int spfa (int n,int sta,int ee)
{
    int vis[Emax],stack[Emax],dis[Emax],vn[Emax];
    memset(vis,0,sizeof(vis));
	memset(dis,0x7f,sizeof dis); 
	memset(vn,0,sizeof vn);
	vn[sta]=1;
    dis[sta] = 0;
    vis[sta] = 1;
    int top = 1;
    stack[0] = sta;
    while (top)
    { 
        int u = stack[--top];
		if(vn[u]>n)
			return -0x7f7f7f7f;
        vis[u] = 0;
        for (int i = head[u];i != -1;i = e[i].next)
        {
            int v = e[i].v;
            if (dis[v] > dis[u] + e[i].w)
            {
                dis[v] = dis[u] + e[i].w;
                if (!vis[v])
                {
                    vis[v] = 1;
					vn[v]++;
                    stack[top++] = v;
                }
            }
        }
    } 
    return dis[ee];
}
int main ()
{ 
    int n,m,v1,v2,cost;
	int ml,md;
	while(scanf("%d",&n)!=EOF)
	{
		cnt = 0;
		memset (head,-1,sizeof(head));
		int minn=0x3f3f3f3f;
		int maxx=0;
		for(int i=0;i<n;i++)
		{
			int u,v,lim;
			scanf("%d%d%d",&u,&v,&lim);
			u++;
			v++; 
			maxx=max(maxx,v);
			minn=min(minn,u);
			addedge(v,u-1,-lim);
		}
		for(int i=minn-1;i<maxx;i++)
		{ 
			addedge(i+1,i,0);
			addedge(i,i+1,1);
        }
		int ans=spfa(maxx-minn+2,maxx,minn-1);
		printf("%d\n",-ans);
	}
	return 0;
}

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值