SCOI2011 糖果 題解

2022-02-13 21:23:32 字數 2890 閱讀 8013

洛谷題面

看到很多題解並沒有講清楚這道題為什麼可以用某些方法,套個板子就沒了。蒟蒻就發一篇題解裝x造福大家吧233

做這道題前,我推薦大家做一下一本通中的1352:【例4-13】獎金一題,因為有可能做完了這道題對於你們會有一點啟發。

題目分析
題目對於小朋友的嫉妒一共有\(5\)中情況,分別如下:

·如果 x=1, 表示第 a 個小朋友分到的糖果必須和第 b 個小朋友分到的糖果一樣多;

·如果 x=2, 表示第 a 個小朋友分到的糖果必須少於第 b 個小朋友分到的糖果;

·如果 x=3, 表示第 a 個小朋友分到的糖果必須不少於第 b 個小朋友分到的糖果;

·如果 x=4, 表示第 a 個小朋友分到的糖果必須多於第 b 個小朋友分到的糖果;

·如果 x=5, 表示第 a 個小朋友分到的糖果必須不多於第 b 個小朋友分到的糖果;

題目想要讓每個小朋友都滿足且使用最少的糖果數量,如果無解則輸出-1。

我們將小朋友當做點,小朋友之間限制條件當做邊

對於x=1、x=3、x=5時,我們不難知道,想要使用最少的糖果數量,那麼最好的方式就是兩個人糖果數量一樣。

對於x=2,那麼a=b-1最優

對於x=4,那麼b=a-1最優

所以說了做一下一本通中的1352:【例4-13】獎金一題對於你們會有一點啟發。

現在我們又可以想到,讓每個小朋友都滿足且使用最少的糖果數量,那麼只需要通過別人對它沒有限制的小朋友,依次更新每個小朋友要有的糖即可。

那麼怎麼去依次找小朋友並更新每個小朋友要的糖呢?

拓撲排序!

怎麼建圖?按什麼條件去建?

比如a要少於b,則建一條a->b的邊,這樣拓撲排序下來,可以保證處理每個點的糖果數量時,可以從小處理到大,符合上面的要求。

那x=1、3、5和x=2、4時有什麼區別呢?

我們就需要額外記錄邊權,x=1、3、5邊權為0,x=2、4邊權為1。

血的教訓:x=1時需要建雙向邊!即a->b且b->a。

為什麼?

因為a必須與b一樣多,那麼我們就可以使用tarjan縮點將兩個點合併為1個點,且將環變為強連通分量。正好滿足了拓撲排序不能有環的性質。

怎麼判斷無解情況?

在建新圖用來拓撲排序時,看兩個點是否在同乙個環內,在且邊權為1則無解。

最重要的乙個問題:怎麼更新糖果數量?

我們將每個人的糖果當做dp[i],在刪i相連的點的入度時,更新i的next的dp值

則有動態轉移方程:

dp[當前更新的點] = max(dp[當前更新的點],dp[當前刪除的點] + nnei[當前刪除的點][第j個鄰居].邊權)

這些知識本人blog中都會涉及的233

那麼思路就很明顯了:

建圖(x=1:建邊權為0的雙向邊,x=2、x=4建邊權為1的單向邊,x=3、x=5時建邊權為0的單向邊)——>tarjan——>邊建新圖邊判斷無解——>用新圖拓撲排序,並更新每個點所需要的糖果數量

**
#includeusing namespace std;

const int maxn = 100000 + 10;

int n,k;

int scc[maxn],sum,low[maxn],dfn[maxn],cnt,tot[maxn];

//以上是強連通圖的必備變數,唯一tot是記錄每個強連通分量裡面有多少個點

int dp[maxn];

//這個用於dp記錄答案

int in[maxn];

//這個記錄入度,用於topo

long long ans;

//最終答案

struct node;

vectornei[maxn];//舊圖

vectornnei[maxn];//新圖

bool stack[maxn];//用於tarjan

stacks;//用於tarjan

inline int read()

while (c >= '0' && c <= '9')

return f * x;

}void tarjan(int u)else

if(stack[next]) }

if(dfn[u] == low[u])

s.pop(); }}

int main()

); nei[y].push_back((node));

//這裡一定要建兩條邊!

break;

}case 2:);

break;

}case 3:);

break;

}case 4:);

break;

}case 5:);

break;

}} }

for(int i = 1;i <= n; i++)

for(int i = 1;i <= n; i++)

if(xx != yy));

in[yy]++;

}} }

queueq;//topo模板

for(int i = 1;i <= sum; i++) }

while(!q.empty()) }

for(int i = 1;i <= sum; i++)

cout<**不做非常詳細的注釋,自己對照前面詳細的講解看看吧233

感謝我的教練 @livedream 幫我debug!

題解 SCOI2011 糖果

依舊是比較明顯的差分約束 注意對於五種操作分別對應的連邊方式 然後注意head的初始值判斷,要不然總是超時 今天遇到好幾次了 建圖時加個小剪枝,否則會tle 1 include2 include3 include4 include5 include6 using namespace std 7con...

SCOI 2011 糖果 SPFA 差分約束

description 幼兒園裡有n個小朋友,lxhgww老師現在想要給這些小朋友們分配糖果,要求每個小朋友都要分到糖果。但是小朋友們也有嫉妒心,總是會提出一些要求,比如小明不希望小紅分到的糖果比他的多,於是在分配糖果的時候,lxhgww需要滿足小朋友們的k個要求。幼兒園的糖果總是有限的,lxhgw...

差分約束詳解 洛谷SCOI2011糖果題解

差分約束系統 如果乙個系統由n個變數和m個約束條件組成,形成m個形如ai aj k的不等式 i,j 1,n k為常數 則稱其為差分約束系統 system of difference constraints 亦即,差分約束系統是求解關於一組變數的特殊不等式組的方法。度娘。然而並沒有看懂。通俗來說,滿足...