題目描述
“人生就像一盒巧克力,你永遠不知道吃到的下一塊是什么味道。”
明明收到了一大塊巧克力,里面有若干小塊,排成n行m列。每一小塊都有自己特別的圖案ci,j,它們有的是海星,有的是貝殼,有的是海螺......其中還有一些因為擠壓,已經分辨不出是什么圖案了。明明給每一小塊巧克力標上了一個美味值ai,j ( 0≤ai,j≤106 ),這個值越大,表示這一小塊巧克力越美味。
正當明明咽了咽口水,准備享用美味時,舟舟神奇地出現了。看到舟舟懇求的目光,明明決定從中選出一些小塊與舟舟一同分享。
舟舟希望這些被選出的巧克力是連通的(兩塊巧克力連通當且僅當他們有公共邊),而且這些巧克力要包含至少k ( 1≤k≤5 )種。而那些被擠壓過的巧克力則是不能被選中的。
明明想滿足舟舟的願望,但他又有點“摳”,想將美味盡可能多地留給自己。所以明明希望選出的巧克力塊數能夠盡可能地少。如果在選出的塊數最少的前提下,美味值的中位數(我們定義n個數的中位數為第⌊n+12⌋小的數)能夠達到最小就更好了。
你能幫幫明明嗎?
輸入格式
從標准輸入讀入數據。
每個測試點包含多組測試數據。
輸入第一行包含一個正整數 T (1≤T≤5),表示測試數據組數。
對於每組測試數據:
輸入第一行包含三個正整數n,m和k;
接下來n行,每行m個整數,表示每小塊的圖案ci,j。若ci,j=−1表示這一小塊受到過擠壓,不能被選中;
接下來n行,每行m個整數,表示每個小塊的美味值ai,j。
輸出格式
輸出到標准輸出。
輸出共包括T行,每行包含兩個整數,用空格隔開,即最少的塊數和最小的美味值中位數。
若對於某組測試數據,不存在任意一種合法的選取方案,請在對應行輸出兩個−1。
數據范圍 n×m≤233 ci,j=−1或1≤ci,j≤n×m
題解:
- 二分一個出現過的美味度做中位數,考慮如何$check$;
- 而判斷一個數$x$>=中位數,只要在數列里面找到至少$\lfloor \frac{n+1}{2} \rfloor$個小於等於$x$的數即可;
- 將$a_{ij}$大於中位樹的設為$1001$,小於等於的設為$999$
- 在滿足連通和顏色的條件下取盡量小的代價和就做到了個數做第一關鍵字,中位數做第二關鍵字;
- 所以每次將(最小值+500)/1000得到個數,將最小值和個數*1000比較,如果小於等於證明合法;
- 具體地求最小值:
- 將顏色在$0-k$內隨機一個新顏色,考慮新顏色$0-k$全都取就取了$k$種,多隨機幾次;
- 每次斯坦納樹求出最小代價;
- $spfa$算滿的話是:$O(T* t *(nm \ 3^{k} + (nm)^2 \ 2^k) )$;
- 感覺整個題充滿了腦洞。。。。
-
(最開始寫的解法里面,等於的設置成1000,在最小個數為偶數的情況下會wa,希望沒有坑到太多人。。。。。)
-
THUSC2017D1T11 #include<bits/stdc++.h> 2 #define inf 0x3f3f3f3f 3 #define fir first 4 #define sec second 5 #define mk make_pair 6 using namespace std; 7 const int N=250; 8 int n,m,k,a[N][N],c[N][N],sub[N],tot,f[N][N][1<<5],id[N][N],col[N],b[N][N],ans1,ans2,vis[N][N]; 9 typedef pair<int,int>pii; 10 queue<pii>q; 11 int dx[4]={0,0,1,-1}; 12 int dy[4]={1,-1,0,0}; 13 void spfa(int s){ 14 while(!q.empty()){ 15 int x=q.front().fir, y=q.front().sec; 16 q.pop();vis[x][y]=0; 17 for(int i=0;i<4;i++){ 18 int nx=x+dx[i], ny=y+dy[i]; 19 if(nx<1||nx>n||ny<1||ny>m||!~c[nx][ny])continue; 20 if(f[nx][ny][s] > f[x][y][s] + b[nx][ny]){ 21 f[nx][ny][s] = f[x][y][s] + b[nx][ny]; 22 if(!vis[nx][ny])vis[nx][ny]=1,q.push(mk(nx,ny)); 23 } 24 } 25 } 26 } 27 void steiner(){ 28 for(int i=1;i<=n;i++) 29 for(int j=1;j<=m;j++){ 30 for(int s=0;s<1<<k;s++)f[i][j][s]=inf; 31 if(~c[i][j])f[i][j][1<<col[c[i][j]]]=b[i][j]; 32 } 33 for(int s=1;s<1<<k;s++){ 34 for(int i=1;i<=n;i++) 35 for(int j=1;j<=m;j++)if(~c[i][j]){ 36 for(int t=s&(s-1);t;t=s&(t-1)){ 37 f[i][j][s] = min(f[i][j][s], f[i][j][t] + f[i][j][s^t] - b[i][j]); 38 } 39 if(f[i][j][s]!=inf)q.push(mk(i,j)),vis[i][j]=1; 40 } 41 spfa(s); 42 } 43 for(int i=1;i<=n;i++) 44 for(int j=1;j<=m;j++)ans1 = min(ans1, f[i][j][(1<<k)-1]); 45 } 46 int main(){ 47 freopen("T1.in","r",stdin); 48 freopen("T1.out","w",stdout); 49 srand(time(NULL)); 50 int T;scanf("%d",&T); 51 while(T--){ 52 scanf("%d%d%d",&n,&m,&k); 53 tot=0; 54 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&c[i][j]); 55 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&a[i][j]),sub[id[i][j]=++tot]=a[i][j]; 56 sort(sub+1,sub+tot+1); 57 tot = unique(sub+1,sub+tot+1) - sub - 1; 58 int l=1,r=tot,fg=0; 59 while(l<r){ 60 int mid=(l+r)>>1; 61 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)b[i][j]=a[i][j]>sub[mid]?1001:/*a[i][j]<sub[mid]?*/999/*:1000*/; 62 ans1 = inf; 63 for(int I=1;I<=400;I++){ 64 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)col[id[i][j]]=rand()%k; 65 steiner(); 66 } 67 if(ans1==inf){fg=1;puts("-1 -1");break;} 68 ans2 = (ans1+500) / 1000; 69 if(ans1 <= ans2 * 1000)r=mid; 70 else l=mid+1; 71 } 72 if(!fg)printf("%d %d\n",ans2,sub[l]); 73 } 74 return 0; 75 }
