日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Coding Contest HDU - 5988

發布時間:2023/12/3 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Coding Contest HDU - 5988 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Coding Contest HDU - 5988

題意:

有n個點,m個邊,每個點有人數和食物數,每個人都要吃一份食物,如果該點的食物不夠,他們就要去其他點,每個邊最多只能走c次,每次有人走一條路,這條路就有p的概率壞掉。第一個人通過時不會壞掉。求最小破壞的電線的概率

題解:

不難看出是一個網絡流,但是不知道該怎么建邊(這也是網絡流最難的部分)
參考題解
每條邊都有走的次數(當作流量),每個邊走一次發生破壞的概率為p(流量1,費用p),我們開始建立費用流圖。根據題意每個邊壞掉概率,如果走多個邊那概率應該相乘,但是費用流往往是累加的,如何將相乘轉成累加?我們可以通過對每個概率取log當成費用,在log下所有都是相加減。
但是題目的概率都是小于1的,如果取log都是負數,費用為負,這跑出來有問題(跑出來的費用會朝著更小走)。如何解決?那么取個負數呢,還是不行,因為取負后最小的變成最大的,跑出來就成最大費用了
此時我們應該這樣考慮,題目要求求最小概率,也就是1-最大概率,因此我們把每條邊的概率賦值為1-p,然后取反取log,這樣跑正好得到的是最小費用,取出來之后再用1減去就好了
add(u,v,f,-log2(1-p)),f為容量,p為概率,從u到v的邊
其他如何建邊:
建立源點s,匯點t,對于S>B(人多),從源點連一條流量為S[i]-B[i],費用為0,對于s<b(糧食多)的,從該點向t連個邊,費用為B[i]-S[i]
題目還說第一次踩不會壞,所以從原有的邊取一條出來,流量為1,費用為0

代碼:

#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<queue> #include<string> #include<functional> typedef long long LL; using namespace std; #define MAXN 110 #define MAXM 25000 #define ll l,mid,now<<1 #define rr mid+1,r,now<<1|1 #define lson l1,mid,l2,r2,now<<1 #define rson mid+1,r1,l2,r2,now<<1|1 #define pi acos(-1.0) #define INF 2e9 const double eps = 1e-8; const int mod = 1e9 + 7; struct Edge {int to, next, cap, flow;double cost; }edge[MAXM]; int head[MAXN], tol; int pre[MAXN]; double dis[MAXN]; bool vis[MAXN]; int N;//節點總個數,節點編號從0~N-1 void init(int n) {N = n;tol = 0;memset(head, -1, sizeof(head)); } void addedge(int u, int v, int cap, double cost) {edge[tol].to = v;edge[tol].cap = cap;edge[tol].cost = cost;edge[tol].flow = 0;edge[tol].next = head[u];head[u] = tol++;edge[tol].to = u;edge[tol].cap = 0;edge[tol].cost = -cost;edge[tol].flow = 0;edge[tol].next = head[v];head[v] = tol++; } bool spfa(int s, int t) {queue<int>q;for (int i = 0; i <= N; i++){dis[i] = INF;vis[i] = false;pre[i] = -1;}dis[s] = 0;vis[s] = true;q.push(s);while (!q.empty()){//cout<<1<<endl; int u = q.front();q.pop();vis[u] = false;for (int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (edge[i].cap > edge[i].flow &&dis[v]-dis[u]-edge[i].cost>eps){dis[v] = dis[u] + edge[i].cost;pre[v] = i;if (!vis[v]){vis[v] = true;q.push(v);}}}}if (pre[t] == -1)return false;else return true; } //返回的是最大流,cost存的是最小費用 int minCostMaxflow(int s, int t, double &cost) {int flow = 0;cost = 0;while (spfa(s, t)){//cout<<1<<endl; int Min = INF;for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]){if (Min > edge[i].cap - edge[i].flow)Min = edge[i].cap - edge[i].flow;}for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to]){edge[i].flow += Min;edge[i ^ 1].flow -= Min;cost += edge[i].cost * Min;}flow += Min;}return flow; } int main() {int t;scanf("%d", &t);while (t--){int n, m;scanf("%d%d", &n, &m);init(n + 1);for (int i = 1; i <= n; i++){int s, b;scanf("%d%d", &s, &b);int f = s - b;//0是源點,n+1是匯點 if (f > 0)///如果人多addedge(0, i, f, 0);else if (f < 0)///如果面包多addedge(i, n + 1, -f, 0);}while (m--){int u, v, f;double w;scanf("%d%d%d%lf", &u, &v, &f, &w);///f是這條路的容量w = -log2(1 - w);///這樣就是正值了if (f > 0)addedge(u, v, 1, 0);///第一個人經過時,不破壞if (f - 1>0)addedge(u, v, f - 1, w);///第大于等于2個人經過時破壞}double cost = 0;minCostMaxflow(0, n + 1, cost);cost = 1 - pow(2, -cost);printf("%.2lf\n", cost);} }

總結

以上是生活随笔為你收集整理的Coding Contest HDU - 5988的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。