bzoj2330糖果(差分約束)
題目描述
幼兒園裡有N個小朋友,lxhgww老師現在想要給這些小朋友們分配糖果,要求每個小朋友都要分到糖果。但是小朋友們也有嫉妒心,總是會提出一些要求,比如小明不希望小紅分到的糖果比他的多,於是在分配糖果的時候,lxhgww需要滿足小朋友們的K個要求。幼兒園的糖果總是有限的,lxhgww想知道他至少需要準備多少個糖果,才能使得每個小朋友都能夠分到糖果,並且滿足小朋友們所有的要求
輸入格式
輸入的第一行是兩個整數N,K。
接下來K行,表示這些點需要滿足的關係,每行3個數字,X,A,B。
如果X=1, 表示第A個小朋友分到的糖果必須和第B個小朋友分到的糖果一樣多;
如果X=2, 表示第A個小朋友分到的糖果必須少於第B個小朋友分到的糖果;
如果X=3, 表示第A個小朋友分到的糖果必須不少於第B個小朋友分到的糖果;
如果X=4, 表示第A個小朋友分到的糖果必須多於第B個小朋友分到的糖果;
如果X=5, 表示第A個小朋友分到的糖果必須不多於第B個小朋友分到的糖果
輸出格式
輸出一行,表示lxhgww老師至少需要準備的糖果數,如果不能滿足小朋友們的所有要求,就輸出-1
樣例輸入
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
樣例輸出
11
分析:
分析:
裸題
最短路——差分約束
定義:
差分約束系統,是求解關於一組變數的特殊不等式組的方法
如果一個系統是由n個變數和m個約束條件組成,
其中每個約束條件形如xj-xi<=bk,則稱其為差分約束條件
解法
求解差分約束系統,
可以轉化為凸輪的單元最短路徑問題
觀察xj-xi<=bk
移項的xj<=xi+bk
很像最短路形式
這樣m條限制就轉化成了m條連線x,y且權值是b的邊(單向邊)
對這個圖執行spfa
最終的dis[i]即為一組可行解
注意
{dis[i]+x}都是合法解
存在負環則無合法解,存在不可到達的點,則存在無限解
spfa怎麼判斷負環呢
有兩種方法:
1)spfa的dfs形式,判斷條件是存在一點在一條路徑上出現多次
2)spfa的bfs形式,判斷條件是存在一點入隊次數大於總頂點數
tip
看了一些前輩的題解
發現這道題好像非常的毒
首先我們需要計算的是最小糖果數
所以要跑一個最大路
開3*n的邊
連邊:單向邊
不等式中<=號左邊的是way.x
建立一個超級源點0
0向n~1連邊(注意順序,不然會T)
注意in的維護
in[y]=in[r]+1、
開ll
在bzoj上就是WA,莫名其妙
辣雞爆炸oj
這裡寫程式碼片
#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int N=100100;
int n,m;
struct node{
int x,y,nxt,v;
};
node way[N*3];
int tot=0,st[N],in[N],q[N],tou,wei,dis[N];
bool p[N];
void add(int u,int w,int z)
{
tot++;
way[tot].x=u;way[tot].y=w;way[tot].v=z;way[tot].nxt=st[u];st[u]=tot;
}
void spfa()
{
int i,j;
bool ff=0;
tou=wei=0;
memset(p,1,sizeof(p));
memset(dis,0xef,sizeof(dis));
dis[0]=0;p[0]=0;
q[++wei]=0; //
do
{
int r=q[++tou];
for (int i=st[r];i;i=way[i].nxt)
{
int y=way[i].y;
if (dis[y]<dis[r]+way[i].v)
{
dis[y]=dis[r]+way[i].v;
in[y]=in[r]+1; ///
if (in[y]>n+1) { //入隊次數過多
printf("-1");
return;
}
if (p[y]){
p[y]=0; q[++wei]=y;
}
}
}
p[r]=1;
}while (tou<wei);
ll ans=0;
for (int i=1;i<=n;i++) ans+=(ll)dis[i];
printf("%lld",ans);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
int opt,u,w;
scanf("%d%d%d",&opt,&u,&w);
if (opt==1){
add(u,w,0); add(w,u,0); //A>=B,B>=A
}
else if (opt==2){
add(u,w,1); //A<=B-1
}
else if (opt==3){
add(w,u,0); //B<=A
}
else if (opt==4){
add(w,u,1); //B<=A-1
}
else{
add(u,w,0); //A<=B
}
}
for (int i=n;i;i--) add(0,i,1); //SS
spfa();
return 0;
}