hdu4888 多校B 最大流以及最大流唯一判斷+輸出方案,hdu4888

來源:互聯網
上載者:User

hdu4888 多校B 最大流以及最大流唯一判斷+輸出方案,hdu4888

題意,給一個矩陣,告訴你每行和、每列和,並且限制所填數不大於k,問矩陣是否唯一。

經典建圖不說了,第一次遇到判斷最大流唯一性的,學習了:用dfs來判斷殘網中是否還存在環,若存在,則表明繞這個環走一圈,(流一圈流量),還是最大流保持不變,說明還有解。輸出方案就EASY了。

WA了一天:第一TLE,因為這題卡DINIC,我的沒有最佳化,後來在zz1215學長加了一行代碼,在增廣的時候,若發現最小總流量已經為0,則標記該點層-1(不必要往下)。效果顯著。原因2:判斷環的時候,dfs判斷環寫錯有木有!不可原諒a!每次枚舉每個進入點(感覺可以最佳化),判斷環,遇到子孩子是祖先就證明有環。

#include<cstdio>        //600ms#include<iostream>#include<queue>#include<cstring>#include<string>using namespace std;const int maxv=910;const int maxe=405*405*2+450;const int inf=0x3f3f3f3f;int n,m,k;int allsumn=0,allsumm=0;int nume=0;int e[maxe][4];int head[maxv];int nsum[405];int msum[405]; bool flag;void inline adde(int i,int j,int c){    e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;    e[nume++][2]=c;    e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;    e[nume++][2]=0;}int lev[maxv];int vis[maxv];int ss=0;int tt=0;bool bfs(){    memset(lev,0,sizeof(lev));    memset(vis,0,sizeof(vis));    queue<int>q;    q.push(ss);    vis[ss]=1;    while(!q.empty())    {        int cur=q.front();        q.pop();        for(int i=head[cur];i!=-1;i=e[i][1])        {            int v=e[i][0];             if(e[i][2]>0&&!vis[v])             {                 lev[v]=lev[cur]+1;               // if(v==tt)return 1;          //這句不加,速度更快                 q.push(v);                 vis[v]=1;             }        }    }    return vis[tt];}int dfs(int u,int minf){    if(u==tt||minf==0)return minf;    int sumf=0,f;    for(int i=head[u];i!=-1&&minf;i=e[i][1])    {        int v=e[i][0];        if(lev[v]==lev[u]+1&&e[i][2]>0)        {            f=dfs(v,e[i][2]<minf?e[i][2]:minf);            sumf+=f;            e[i][2]-=f;e[i^1][2]+=f;            minf-=f;        }    }    if(!sumf)lev[u]=-1;              //關鍵最佳化!    return sumf;}int dinic(){    int sum=0;    while(bfs())      sum+=dfs(ss,inf);    return sum;}void init(){    allsumm=allsumn=nume=0;   memset(head,-1,sizeof(head));    ss=n+m;tt=n+m+1;}void read_build(){     for(int j=0;j<n;j++)          {              scanf("%d",&nsum[j]);              allsumn+=nsum[j];          }     for(int j=0;j<m;j++)         {            scanf("%d",&msum[j]);             allsumm+=msum[j];         }     for(int i=0;i<n;i++)       for(int j=0;j<m;j++)       {           adde(i,j+n,k);       }      for(int i=0;i<n;i++)      {          adde(n+m,i,nsum[i]);      }      for(int i=0;i<m;i++)      {          adde(i+n,n+m+1,msum[i]);      }}bool dfs_getother_ans(int u,int fa){      if(flag)return 1;      for(int i=head[u];i!=-1;i=e[i][1])    {        int v=e[i][0];        if(v==fa||e[i][2]<=0||v==n+m||v==n+m+1)continue;        if(!vis[v])        {            vis[v]=1;            dfs_getother_ans(v,u);            vis[v]=0;                           //出來的時候標記回來啊!        }        else        {             flag=1;            return 1;        }        if(flag)return 1;    }    return 0;}int ansjz[405][405];int main(){    while(scanf("%d%d%d",&n,&m,&k)!=EOF)    {       init();       read_build();       if(allsumm!=allsumn)          {printf("Impossible\n");continue;}       int ans=dinic();       if(ans!=allsumm)        {            printf("Impossible\n");        }       else       {            flag=0;         for(int i=0;i<n;i++)         {              vis[i]=1;                 if(dfs_getother_ans(i,-1))                 {                     flag=1;                     break;                 }              vis[i]=0;            }         if(flag)           printf("Not Unique\n");         else         {             printf("Unique\n");             for(int i=0;i<=n-1;i++)                   for(int j=head[i];j!=-1;j=e[j][1])                   {                      if(j%2==0)                      {                         ansjz[i][e[j][0]-n]=k-e[j][2];                      }                   }            for(int i=0;i<n;i++)                for(int j=0;j<m;j++)                   if(j==m-1)printf("%d\n",ansjz[i][j]);                   else printf("%d ",ansjz[i][j]);         }        }    }    return 0;}



急 數學建模最大流問題——運輸網路

<第一歩 建立限制式>
對於每一條線段的流量,建立出限制式,如:
S_a <= 26
S_b <= 12
a_b <= 5
....

<第二歩先利用流量瓶頸將限制式轉化為等號>
(1)將 c_f, d_f, d_g, e_g 切斷,則S 將無法連通 M1, M2, M3 所以 c_f, d_f, d_g, e_g 為溝通左右的橋樑組合之一.
(2)已知全部需要傳遞的總噸數為 10 + 8 + 8 = 26 ,其中 10 噸給M1,8 噸給M2,8 噸給M3
(3)又 c_f, d_f, d_g, e_g 四個流量的總和為 10 + 6 + 5 + 5 = 26 故 c_f, d_f, d_g, e_g 四個流量都要用完,因此可以寫成下列四個等式:
(4) c_f = 10, d_f = 6, d_g = 5, e_g = 5

<第三歩 切割問題成兩部分>
(1)依據 c_f=10 且 d_f=6 ,得知 f 點會獲得 16 噸貨物
   依據 d_g=5 且 e_g=5 ,得知 g 點會獲得 10 噸貨物
   依此可以建立<子問題A>,即:
   ----------------------------------
   如何將 f 點的16 噸與 g 點的10 噸,分送給M1, M2, M3 且量為10, 8, 8
   ----------------------------------
(2)依據 c_f=10 ,得知 c 點會獲得 10 噸貨物
   依據 d_f=6 且 d_g=5​​ ,得知 d 點會獲得 11 噸貨物
   依據 e_g=5 ,得知 e 點會獲得 5 噸貨物
   依此可以建立<子問題B>,即:
   ----------------------------------
   如何將 S 點的東西,分送到 c, d, e 且量為10, 11, 5
   ----------------------------------

<第四歩 解決子問題A>
(1)g 點的10 噸貨物只能傳向M3 ,M3 領收8 噸之後,剩下的2 噸只能傳給M2 .傳遞完畢之後,g_M3 之間的流量還剩 15-10=5 ,M3_M2 之間的流量還剩 5-2=3
(2)M1 只能靠 f 點提供貨物,所以 M1 所需的10 噸必須完全通過 f_M1 之間的連線
(3)最後 f 還剩下6 噸貨物要傳給 M2 ,這可以完全通過上方的 f_M1 連線完成;也可以通過下方的 f_g 連線,分流 3 噸以下的物資過去(別忘了M3_M2 之間只剩下3 噸的餘額).
承上,<子問題A>獲得解決.

<第五歩 解決子問題B>
(1)c 點的 10 噸貨物必須來自於a ,故 a_c 的流量還剩下 20-10=10
(2)e 點的 5 噸貨物必須來自於b ,故 b_e 的流量還剩下 6-5=1
(3)d 點的 11 噸貨物可能來自於 c, b, e .
 (3-1)由於 c_d 的流量限制,c 點最多隻能提供 d 點5 噸
 (3-2)由於 b_d 的流量限制,b 點最多隻能提供 d 點5 噸
 (3-3)由於 b_e 的流量限制(參考上述第2點),e 點最多隻能提供 d 點1 噸
 (3-4)所以 d 點的貨物來源是唯一的:b 與c 各給5 噸,e 給1 噸
(4)結合第1點與第3-1點,a 點全部需要提供 10+5 = 15 噸
(5)結合第2點、第3-2點、第3-3點,b 點全部需要提供 5+5+1 = 11......餘下全文>>
 
最大流問題建模

<第一歩 建立限制式>
對於每一條線段的流量,建立出限制式,如:
S_a <= 26
S_b <= 12
a_b <= 5
....

<第二歩先利用流量瓶頸將限制式轉化為等號>
(1)將 c_f, d_f, d_g, e_g 切斷,則S 將無法連通 M1, M2, M3 所以 c_f, d_f, d_g, e_g 為溝通左右的橋樑組合之一.
(2)已知全部需要傳遞的總噸數為 10 + 8 + 8 = 26 ,其中 10 噸給M1,8 噸給M2,8 噸給M3
(3)又 c_f, d_f, d_g, e_g 四個流量的總和為 10 + 6 + 5 + 5 = 26 故 c_f, d_f, d_g, e_g 四個流量都要用完,因此可以寫成下列四個等式:
(4) c_f = 10, d_f = 6, d_g = 5, e_g = 5

<第三歩 切割問題成兩部分>
(1)依據 c_f=10 且 d_f=6 ,得知 f 點會獲得 16 噸貨物
   依據 d_g=5 且 e_g=5 ,得知 g 點會獲得 10 噸貨物
   依此可以建立<子問題A>,即:
   ----------------------------------
   如何將 f 點的16 噸與 g 點的10 噸,分送給M1, M2, M3 且量為10, 8, 8
   ----------------------------------
(2)依據 c_f=10 ,得知 c 點會獲得 10 噸貨物
   依據 d_f=6 且 d_g=5​​ ,得知 d 點會獲得 11 噸貨物
   依據 e_g=5 ,得知 e 點會獲得 5 噸貨物
   依此可以建立<子問題B>,即:
   ----------------------------------
   如何將 S 點的東西,分送到 c, d, e 且量為10, 11, 5
   ----------------------------------

<第四歩 解決子問題A>
(1)g 點的10 噸貨物只能傳向M3 ,M3 領收8 噸之後,剩下的2 噸只能傳給M2 .傳遞完畢之後,g_M3 之間的流量還剩 15-10=5 ,M3_M2 之間的流量還剩 5-2=3
(2)M1 只能靠 f 點提供貨物,所以 M1 所需的10 噸必須完全通過 f_M1 之間的連線
(3)最後 f 還剩下6 噸貨物要傳給 M2 ,這可以完全通過上方的 f_M1 連線完成;也可以通過下方的 f_g 連線,分流 3 噸以下的物資過去(別忘了M3_M2 之間只剩下3 噸的餘額).
承上,<子問題A>獲得解決.

<第五歩 解決子問題B>
(1)c 點的 10 噸貨物必須來自於a ,故 a_c 的流量還剩下 20-10=10
(2)e 點的 5 噸貨物必須來自於b ,故 b_e 的流量還剩下 6-5=1
(3)d 點的 11 噸貨物可能來自於 c, b, e .
 (3-1)由於 c_d 的流量限制,c 點最多隻能提供 d 點5 噸
 (3-2)由於 b_d 的流量限制,b 點最多隻能提供 d 點5 噸
 (3-3)由於 b_e 的流量限制(參考上述第2點),e 點最多隻能提供 d 點1 噸
 (3-4)所以 d 點的貨物來源是唯一的:b 與c 各給5 噸,e 給1 噸
(4)結合第1點與第3-1點,a 點全部需要提供 10+5 = 15 噸
(5)結合第2點、第3-2點、第3-3點,b 點全部需要提供 5+5+1 = 11......餘下全文>>
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.