WC2007 剪刀石頭布 Solution

2021-10-01 18:37:54 字數 2247 閱讀 2237

給一張競賽圖,圖中還有一些邊沒有定向,現在要把它們重新定向,要求重定向之後三元環盡量多。

直接考慮不可取,逆向思維。算出極限情況可能出現三元環的個數,那麼就是n×(

n−1)

×(n−

2)

6\dfrac

6n×(n−

1)×(

n−2)

​,接下來考慮什麼情況會拆毀三元環。

考慮乙個點的負場情況來判斷少了多少三元環。

如果乙個點負場為2

22或更多,那麼只要從能打過它的點裡面隨便挑出兩個點就不是乙個三元環。

按照本類題目的一般做法來做的話,把那些沒定向的邊看為點,稱之為邊對應的點,那麼就可以這樣建圖:

那麼之後邊對應的點流向那個點就表明設定的是那個人輸了。

那麼接下來就要考慮人如何連到匯點了。直接做一條邊顯然是不可行的。

考慮乙個點從x

xx負場到x+1

x+1x+

1負場會破壞多少三元環。

那麼就是x×(

x+1)

2−x×

(x−1

)2=x

\dfrac-\dfrac=x

2x×(x+

1)​−

2x×(

x−1)

​=x。

所以我們可以考慮拆邊。

讓乙個人往匯點連上n

nn條邊,第i

ii條邊流量為1

11,費用為iii。

這樣就可以了。

c od

e:

code:

code

:

#include

#define regi register int

int n;

int s,t;

int ans;

int mincost;

int vis[

100100];

int win[

100100];

int dis[

100100];

std::queue<

int>q;

int a[

1000][

1000];

int be[

10100][

110]

;int head[

100100

],tot=1;

struct edgee[

100000];

void

add(

int x,

int y,

int flow,

int cost)

; head[x]

=tot;

e[++tot]=;

head[y]

=tot;

}bool

spfa()

q.push

(s);

dis[s]=0

;while

(!q.

empty()

)}}}

return dis[t]

!=0x3f3f3f3f;}

intdfs

(int x,

int min)

vis[x]=1

;int flow=0;

for(regi i=head[x]

,w;i;i=e[i]

.nxt)

}return flow;

}void

dinic()

}}main()

}//先算出現在少了多少三元環

for(regi i=

1;i<=n;

++i)

//拆邊,按照等差數列建邊。

dinic()

;//跑圖。

printf

("%d\n"

,ans-mincost)

;for

(regi i=

1;i<=n;

++i)

for(regi j=i+

1;j<=n;

++j)

}//檢索哪條邊流滿了。

for(regi i=

1;i<=n;

++i,

puts(""

))for(regi j=

1;j<=n;

++j)

printf

("%d "

,a[i]

[j])

;return0;

}

Wc2007 剪刀石頭布

題目描述 bzluogu 題解 最小費用流。對於三支隊伍,勝負情況只有 2 種。一種是形成三元環,另一種是 x 贏兩場,y 贏一場,z 沒贏過。所以我們統計一下另一種最少有多少種就好了。最後答案就是 c 3 n k 對於乙個隊伍 x 若其勝場數為 w x 則會造成的負貢獻為 c 2 不會搞?作差啊。...

WC2007 剪刀石頭布

正著求不太好求,但是不是剪刀石頭布的又很好表示 三個人中恰好有乙個人贏了兩場。所以我們考慮讓這種三元組數量最少使得剪刀石頭布最多。考慮乙個人如果贏了i場,那麼他對 非剪刀石頭布的三元組的貢獻是 i i 1 2 也就是他和任意兩個被他擊敗的人都可以組成三元組。並且每個人的貢獻都是獨立的,不會有重複 因...

Wc2007 剪刀石頭布(費用流)

time limit 20 sec memory limit 128 mb sec special judge 在一些一對一遊戲的比賽 如下棋 桌球和羽毛球的單打 中,我們經常會遇到a勝過b,b勝過c而c又勝過a的有趣情況,不妨形象的稱之為剪刀石頭布情況。有的時候,無聊的人們會津津樂道於統計有多少這...