【解題報告】洛谷P3275 糖果
阿新 • • 發佈:2021-10-06
【解題報告】洛谷P3275 糖果
原題連結
https://www.luogu.com.cn/problem/P3275
思路
在這樣天氣寒冷的日子裡,怎麼能不做題呢~!
天氣陰涼,我懷著激動的心情打開了這道題目
題意大概滿足一堆要求,讓你求一個滿足要求的所有的變數的和
自己看去吧
然後我們讀題發現,這不就是一個差分約束嗎?
待會?
差分約束滿足的形式是這樣的
\[x_i-x_{i'} \le y_i \]所以題目中不少於不多於的都非常好搞,直接連邊就可以了
那剩下的怎麼搞呢?
首先等於,等於的話我們可以雙向連邊,一個不大於,一個不小於,不就是等於了嗎?
然後後面呢?
我們實際上可以他們變成 \(A \le B-1\)
然後我們用一個 \(SPFA\) 跑就可以了
有一個玄學的東西,就是我們在跑的時候要對於超級源點從大邊向小邊連邊,不然會被卡掉,或者連邊的同時把連得邊都 push
一下也可以似乎?
我不知道為啥,但是我過了
別人也不知道為啥,我就寫在了這裡qaq
std
本博文為wweiyi原創,若想轉載請聯絡作者,qq:2844938982#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> #include <queue> #define int long long using namespace std; const int maxn=300005; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') f=-1; c=getchar(); } while(c>='0'&&c<='9') { x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } return x*f; } struct edge{ int e,next,val; }ed[maxn<<1]; int en,first[maxn]; void add_edge(int s,int e,int val) { en++; ed[en].next=first[s]; first[s]=en; ed[en].e=e; ed[en].val=val; } int n,k; int d[maxn],num[maxn]; bool vis[maxn]; queue <int> q; bool spfa(int s) { d[s]=0; vis[s]=true; q.push(s); num[s]++; while(q.size()) { int x=q.front(); q.pop(); vis[x]=false; for(int i=first[x];i;i=ed[i].next) { int e=ed[i].e; int val=ed[i].val; if(d[e]<d[x]+val) { d[e]=d[x]+val; if(!vis[e]) { vis[e]=true; q.push(e); num[e]++; if(num[e]==n+1) return false; } } } } return true; } signed main() { memset(d,-0x3f3f3f,sizeof(d)); n=read(),k=read(); for(int i=1;i<=k;i++) { int x=read(),a=read(),b=read(); if(x==1) { add_edge(b,a,0);//a<=b add_edge(a,b,0);//a>=b; } else if(x==2) { if(a==b) { cout<<-1<<'\n'; return 0; } add_edge(a,b,1);//a<b } else if(x==3) { add_edge(b,a,0);//a>=b } else if(x==4) { if(a==b) { cout<<-1<<'\n'; return 0; } add_edge(b,a,1);//a>b } else if(x==5) { add_edge(a,b,0);//a<=b } } for(int i=n;i>=1;i--) add_edge(0,i,1);//q.push(i); if(!spfa(0)) { cout<<-1<<'\n'; return 0; } int ans=0; for(int i=1;i<=n;i++) ans+=d[i]; cout<<ans<<'\n'; return 0; }