1. 程式人生 > >BZOJ 3168 [Heoi2013]鈣鐵鋅硒維生素

BZOJ 3168 [Heoi2013]鈣鐵鋅硒維生素

跟著 algorithm 一次 貪心 printf 字符 只需要 std 之間

Description

銀河隊選手名單出來了!小林,作為特聘的營養師,將負責銀河隊選手參加宇宙比賽的飲食。眾所周知,前往宇宙的某個星球,通常要花費好長好長的時間,人體情況在這之間會發生變化,因此,需要根據每天的情況搭配夥食,來保證營養。小林把人體需要的營養分成了n種,這些營養包括但不限於鐵,鈣。他準備了2套廚師機器人,一套廚師機器人有n個,每個廚師機器人只會做一道菜,這道菜一斤能提供第i種營養xi微克。想要吃這道菜的時候,只要輸入一個數,就能吃到對應數量的這道菜了。為防止攝入過量對身體造成的傷害,每個機器人還有防過量攝入藥,只要輸入一個數,就能生成一定劑量的藥,吃了這些藥,就能減少相當於食用對應數目的這道菜提供的營養。小林之所以準備2套廚師機器人,正是因為旅途漫漫,難以預計,也許某一個廚師機器人在途中壞掉,要是影響了銀河隊選手的身體,就不好了。因此,第2套廚師機器人被用來做第1套的備用。小林需要為每一個第1套廚師機器人選一個第2套廚師機器人作備份,使得當這個機器人壞掉時,用備份頂替,整套廚師機器人仍然能搭配出任何營養需求,而且,每個第2套廚師機器人只能當一個第1套廚師機器人的備份。

Input

第一行包含一個正整數n。 接下來n行,每行n個整數,表示第1套廚師機器人做的菜每一斤提供的每種營養。 再接下來n行,每行n個整數,表示第2套廚師機器人做的菜每一斤提供的每種營養。 1≤n≤300,所有出現的整數均非負,且不超過10,000。

Output

第一行是一個字符串,如果無法完成任務,輸出“NIE”,否則輸出“TAK” 並跟著n行,第i行表示第i個第1套機器人的備份是哪一個第2套機器人。 為了避免麻煩,如果有多種可能的答案,請給出字典序最小的那一組。

Sample Input

3
1 0 0
0 1 0
0 0 1
2 3 0
0 7 8
0 0 9

Sample Output

TAK
1
2
3

這道題是在找二分圖相關的題時候找到的,看了以後發現建圖才是關鍵。題意一開始並沒有理解清楚,一定要仔細讀題,一定要仔細讀題,一定要仔細讀題。

題目一開始給了兩個矩陣A,B,其實就是看B的某一行能代替A的哪些行,通過這個建圖,之後直接跑最大匹配驗證一下就可以了。這樣我們把矩陣A看作是n個向量,每一行都代表一個n維向量,以他們建立n維坐標系,因為題目保證一開始能搭配出任何營養需求,那就是說這個n維空間每個地方都可以被這些向量所表示出來,而且這樣的話矩陣A就顯然是一個滿秩矩陣了,並且B替換A的一行時,還要保證換完以後A還是一個滿秩矩陣。

之後我們設出一個系數矩陣C,使得C * A = B,我們現在想C的實際意義,AB中每個機器人對應著一個行向量,所以行向量對應 就需要是CA=B而不是AC=B,如果說C的某一個位置是0 (假設是第i行 第j列),那麽也就意味著並不用A中的第j行來表示B中的第i行,這兩個行向量是無關的。或者可以理解成,在這個n維空間裏,這兩個向量是垂直的,也就是我們不能用矩陣B的第i行來代替矩陣A的第j行。

這樣只需要求出C就可以了,只要C(i,j) != 0那麽B的第i行就能夠代替A的第j行 。由於題目保證A是滿秩的,所以可以直接求A的逆矩陣A-1,可得C=B A-1依此建圖即可,不過題目要求是A的代替方案字典序最小,所以實際建圖的鄰接矩陣是C的轉置矩陣。

跑二分圖匹配由於要求字典序最小,所以跑完美匹配,如果可行,再去由小到大貪心的去換邊,也就是再跑一次匈牙利算法。(有人說實際上數據並沒有保證A是滿秩的,所以高斯消元的時候判斷一下。)

下面是代碼:(比較醜)

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<cmath>
  6 using namespace std;
  7 double a[310][310],b[310][310],c[310][310],ni[310][310];
  8 int n,mat[310],ans[310];
  9 bool vis[310],nxt[310][310];
 10 bool ling(double x){
 11     if(fabs(x)<1e-8) return true;
 12     return false;
 13 }
 14 bool gauss(){
 15     int i,j,k;
 16     double t;
 17     for(i=1;i<=n;i++){
 18         for(j=i;j<=n;j++) if(ling(a[j][i])==false) break;
 19         if(i!=j) for(k=1;k<=n;k++) swap(a[i][k],a[j][k]),swap(ni[i][k],ni[j][k]);
 20         if(ling(a[i][i])==true) return false;
 21         t=1/a[i][i];
 22         for(k=1;k<=n;k++) a[i][k]*=t,ni[i][k]*=t;
 23         for(j=1;j<=n;j++){
 24             if(i==j) continue;
 25             t=a[j][i];
 26             for(k=1;k<=n;k++){
 27                 a[j][k]-=a[i][k]*t;
 28                 ni[j][k]-=ni[i][k]*t;
 29             }
 30         }
 31     }
 32     return true;
 33 }
 34 void jucheng(){
 35     int i,j,k;
 36     for(i=1;i<=n;i++){
 37         for(j=1;j<=n;j++){
 38             for(k=1;k<=n;k++){
 39                 c[i][j]+=b[i][k]*ni[k][j];
 40             }
 41         }
 42     }
 43     for(i=1;i<=n;i++){
 44         for(j=1;j<=n;j++){
 45             if(ling(c[i][j])==false) nxt[j][i]=true;
 46             else nxt[j][i]=false;
 47         }
 48     }
 49 }
 50 bool dfs1(int pos){
 51     for(int i=1;i<=n;i++){
 52         if(nxt[pos][i]==false||vis[i]==false) continue;
 53         vis[i]=false;
 54         if(mat[i]==0||dfs1(mat[i])==true){
 55             mat[i]=pos;
 56             ans[pos]=i;
 57             return true;
 58         }
 59     }
 60     return false;
 61 }
 62 bool dfs2(int pos,int frm){
 63     for(int i=1;i<=n;i++){
 64         if(nxt[pos][i]==false||vis[i]==false) continue;
 65         vis[i]=false;
 66         if(mat[i]==frm||(mat[i]>frm&&dfs2(mat[i],frm)==true)){
 67             mat[i]=pos;
 68             ans[pos]=i;
 69             return true;
 70         }
 71     }
 72     return false;
 73 }
 74 int main()
 75 {
 76     int i,j;
 77     scanf("%d",&n);
 78     for(i=1;i<=n;i++){
 79         for(j=1;j<=n;j++){
 80             scanf("%lf",&a[i][j]);
 81         }
 82     }
 83     for(i=1;i<=n;i++){
 84         for(j=1;j<=n;j++){
 85             scanf("%lf",&b[i][j]);
 86         }
 87     }
 88     memset(c,0,sizeof(c));
 89     memset(ni,0,sizeof(ni));
 90     memset(mat,0,sizeof(mat));
 91     for(i=1;i<=n;i++) ni[i][i]=1;
 92     if(gauss()==false){
 93         printf("NIE\n");
 94         return 0;
 95     }
 96     jucheng();
 97     for(i=1;i<=n;i++){
 98         memset(vis,true,sizeof(vis));
 99         if(dfs1(i)==false){
100             printf("NIE\n");
101             return 0;
102         }
103     }
104     for(i=1;i<=n;i++){
105         memset(vis,true,sizeof(vis));
106         dfs2(i,i);
107     }
108     printf("TAK\n");
109     for(i=1;i<=n;i++) printf("%d\n",ans[i]);
110 }

BZOJ 3168 [Heoi2013]鈣鐵鋅硒維生素