poj 1112 經典最小差值dp(超級好題)

2021-10-03 21:25:12 字數 3056 閱讀 7970

題意:

給你n個人,告訴你誰認識誰。要求將他們分成兩組,每組的人相互都認識,且每組人數盡量接近(人數的差值最小)。

輸入:第一行輸入有幾個人,第i行表示第i-1個人認識那些人,0表示結束。

輸出:共兩行,第i行第乙個數表示i組有多少個人,然後依次輸出這幾個人,第二行同理。

sample input

52 3 5 0

1 4 5 3 0

1 2 5 0

1 2 3 0

4 3 2 1 0

sample output

3 1 3 5

2 2 4

思路:先抽象成二分圖,然後看能不能二分,如果不能直接輸出,如果能,就抽象成可以dp的問題,用dp找差值最小的解。

抽象過程:

對於每乙個節點,都有跟他相互連線的一堆節點,組成乙個強連通分量,然後給這個強連通分量染色。問題就抽象成了這樣,

有t個物品,每個物品有u價值和v價值,同時你可以選擇將物品的u價值和v價值可以互換(swap(u,v)),對於每種物品,你都可以選擇換或者不換。su = u價值的和,sv等於v價值的和,求abs(su-sv)最小時,所有物品換了或者沒換。

初步定義dp[i]表示前i個物品的最小abs(su-sv)

再次定義dp[i][j]表示前i種物品能否構成差值為j的解,

這樣定義的話,可行解可以推出可行解,狀態轉移方程就很明顯了。

下面直接上**

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define inf 0x3f3f3f3f

#define linf 0x3f3f3f3f3f3f3f3f

#define ll long long

#define ull unsigned long long

#define uint unsigned int

#define l(x) ((x)<<1)

#define r(x) ((x)<<1|1)

#define lowbit(x) ((x)&(-(x)))

#define ms(a,b) memset(a,b,sizeof(a))

#define nsync std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);

using

namespace std;

const

int maxn =

110;

int n;

//有多少個節點

int total;

//有多少個強連通分量

int g[maxn]

[maxn]

;//i節點和j節點是否相連

int color[maxn]

;//第i個節點的值(顏色)是多少

int col[maxn][3

];//第i個分量裡值為j的節點有幾個

int mark[maxn][3

][maxn]

;//第i個分量裡值為j的第k個節點是誰

int f[maxn]

[maxn *2]

;//前i個連通分量能不能構成差值為j

int path[maxn]

[maxn *2]

;//用於記錄最優解是怎麼構成的

intdfs

(int u)}}

return1;

}int

main()

}int a1, a2;

ms(f,0)

; f[1]

[col[1]

[1]- col[1]

[2]+ n]=1

; f[1]

[col[1]

[2]- col[1]

[1]+ n]=1

; path[1]

[col[1]

[1]- col[1]

[2]+ n]=1

; path[1]

[col[1]

[2]- col[1]

[1]+ n]=2

;for

(int i =

2; i <= total; i++

)elseif(

(j + a)

>=0&&

(j + a)

<=

2* n&&

f[i -1]

[j + a]==1

)}}int i, j;

for(i = n; i <=

2* n; i++)if

(f[total]

[i])

break

;for

(j = n -

1; j >=

0; j--)if

(f[total]

[j])

break

;int ans =

(i - n)

<

(n - j)

? i : j;

int tro =

((n -

(ans - n))/

2)+(ans - n)

;printf

("%d"

, tro)

;int loc;

tem = ans;

for(

int i = total; i >=

1; i--

) tem = ans;

printf

("\n");

printf

("%d"

, n - tro)

;for

(int i = total; i >=

1; i--

)printf

("\n");

return0;

}

2009最經典名句

1 我的優點是 我很帥 但是我的缺點是 我帥的不明顯.2 談錢不傷感情,談感情最他媽傷錢。3 我詛咒你一輩子買速食麵沒有調料包。4 會計說 你晚點來領工資吧,我這沒零錢。5 雖然你身上噴了古龍水,但我還是能隱約聞到一股人渣味兒。6 有一次我上街,一群女孩把我攔住,她們說我帥,我不承認,她們就打我,還...

最經典的笑話

有乙個修女到神父那裡懺悔 神父,請您原諒我,我昨天辱罵了乙個男人。神父 你罵他什麼?修女 我罵他 你媽了個bi 神父 你為什麼要罵他呢,告訴我,我會請求上帝原諒你的。修女 她摸我的胸部。神父把手伸進了修女的胸部 是這樣嗎?修女 是的。神父 即使他摸了你的胸,你也不應該罵他啊。修女 可是他又接著往下摸...

volitale最經典理解

volatile保證了執行緒之間的可見性 因為執行緒看到volatile變數會去讀取主記憶體最新的值,而不是自個一直在那跟內部的變數副本玩,所以保證了valatile變數在各個執行緒間的可見性。volatile保證了執行緒之間的可見性 因為執行緒看到volatile變數會去讀取主記憶體最新的值,而不...