乙個整數表示聯盟裡所有球隊收益之和的最小值。
3 31 0 2 1
1 1 10 1
0 1 3 3
1 22 3
3 143
solution
設n為當前winsum,m為當前losesum
這道題 有用的性質:
1.不管 輸還是贏 增加的收益永遠是遞增的
ci*(n+1)^2-ci*n^2=2*n+1
2.對於單個的一支球隊來說,贏得永遠比輸的收益多
技巧:由於從比賽節點 向球隊結點連一條邊之後,還會有兩種情況,根本無法加權值
所以先假設比賽的雙方都輸,然後改的時候只需要改贏得一方
贏得一方 增加的收益=ci*(win+1)^2+di(lose-1)^2-ci*win^2-di*lose^2
建圖:s=0 t=n+m+1
1.s向每場比賽連 w=1 cost=0 的邊
2.每場比賽向比賽雙方連 w=1 cost=0 的邊
3.記錄下每個球隊參加的比賽場數 s
每個球隊 向t依次連 s條邊,w=inf,cost按照一開始的winsum依次加 (這個比較難理解)
這樣加保證 既選擇了最小費用,又不會影響對手的最小費用 (從球隊向t依次連了多條邊)(大佬命名其為拆邊法)
最後跑mcmf即可
1 #include2 #include3 #include4 #include5mk a_leaf#define mem(a,b) memset(a,b,sizeof(a))
6#define ll long long
7#define dd double
8using
namespace
std;
9const
int inf=(1
<<31)-1
;10 inline int minn(int a,int b)
11struct
son12
;16 son a1[1000006
];17
int first[1000006
],e;
18void addbian(int u,int v,int w,int
cost)
1927
void link(int u,int v,int w,int
cost)
2832
33int
n,m,u,o;
34int win[5006],lose[5006],c[5006],d[5006
];35
int a[5006],b[5006
];36
ints,t;
37int
ans;
3839
int flow[8006],flag[8006],d[8006],pre[8006
];40 queueq;
41bool spfa(int &fw,int &ct)
4261}62
}63if(d[t]==qqq)return0;
64 fw+=flow[t];
65 ct+=d[t]*flow[t];
66int now=t;
67while(now!=s)
6873
return1;
74}7576
intmcmf()
7782
83void
out11()
8493 printf("\n"
);94}95
96int
main()
108for(int i=1;i<=n;++i)
109 ans+=( c[i]*win[i]*win[i]+d[i]*lose[i]*lose[i] );
110for(int i=1;i<=m;++i)
111119
//out11();
120//
cout<<0;
121 printf("
%d",ans+mcmf());
122//
while(1);
123return0;
124 }
JSOI2009 bzoj1449 球隊收益
description input output 乙個整數表示聯盟裡所有球隊收益之和的最小值。首先假設全輸,然後給每場比賽分配乙個贏家,每個隊伍每多贏一場多獲得的收益作為費用。但是有乙個問題,如何保證每次走的是對應的邊?也就是,如何保證贏第一場的時候增加的收益是贏一場減贏零場,而不是贏兩場減贏一場?...
bzoj1449 JSOI2009 球隊收益
傳送門 感覺就是費用流呀。可以發現這道題與之前的費用流題有所不同,因為乙個球隊不論輸還是贏都會獲得收益。這裡就要用到乙個技巧,我們可以假裝比賽雙方都輸,然後修改贏的就ok辣。然後就是每個人向終點連邊,這裡的費用隨著流量的變化而變化,所以我們要用到拆邊法。考慮乙個人從贏win i 次 輸lose i ...
BZOJ1449 JSOI2009 球隊收益
bzoj luogu 在乙個籃球聯賽裡,有 n 支球隊,球隊的支出是和他們的勝負場次有關係的,具體來說,第i支球隊的賽季總支出是 c i times x 2 d i times y 2,d i le c i 其中 x,y 分別表示這只球隊本賽季的勝負場次。現在賽季進行到了一半,每只球隊分別取得了 a...