【UVA658】It's not a Bug, it's a Feature!——楊子曰題目

【洛谷P2761】軟件補丁問題——楊子曰題目

喂喂喂,大標題和文章標題不一樣!!
呵呵,同一道題……(就是如此神奇)


這裏貼的是【洛谷P2761】軟件補丁問題,其實就是uva那道題的翻譯:

題目描述
T 公司發現其研製的一個軟件中有 n 個錯誤,隨即爲該軟件發放了一批共 m 個補丁程序。每一個補丁程序都有其特定的適用環境,某個補丁只有在軟件中包含某些錯誤而同時又不包含另一些錯誤時纔可以使用。一個補丁在排除某些錯誤的同時,往往會加入另一些錯誤。

換句話說,對於每一個補丁 i,都有 2 個與之相應的錯誤集合 B1[i]和 B2[i],使得僅當軟件包含 B1[i]中的所有錯誤,而不包含 B2[i]中的任何錯誤時,纔可以使用補丁 i。補丁 i 將修復軟件中的某些錯誤 F1[i],而同時加入另一些錯誤 F2[i]。另外,每個補丁都耗費一定的時間。

試設計一個算法,利用 T 公司提供的 m 個補丁程序將原軟件修復成一個沒有錯誤的軟件,並使修復後的軟件耗時最少。對於給定的 n 個錯誤和 m 個補丁程序,找到總耗時最少的軟件修復方案。

輸入輸出格式
輸入格式:
第 1 行有 2 個正整數 n 和 m,n 表示錯誤總數,m表示補丁總數,1<=n<=20, 1<=m<=100。

接下來 m 行給出了 m 個補丁的信息。每行包括一個正整數,表示運行補丁程序 i 所需時間,以及 2 個長度爲 n 的字符串,中間用一個空格符隔開。

第 1 個字符串中,如果第 k 個字符 bk 爲“+”,則表示第 k 個錯誤屬於 B1[i],若爲“-”,則表示第 k 個錯誤屬於 B21[i],若爲“0”,則第 k 個錯誤既不屬於 B1[i]也不屬於 B2[i],即軟件中是否包含第 k 個錯誤並不影響補丁 i 的可用性。

第 2 個字符串中,如果第 k 個字符 bk爲“-”,則表示第 k 個錯誤屬於 F1[i],若爲“+”,則表示第 k 個錯誤屬於 F2[i],若爲“0”,則第 k 個錯誤既不屬於 F1[i]也不屬於 F2[i],即軟件中是否包含第 k 個錯誤不會因使用補丁i 而改變。

輸出格式:
程序運行結束時,將總耗時數輸出。如果問題無解,則輸出 0。

輸入樣例:

3 3
1 000 00-
1 00- 0-+
2 0-- -++

輸出樣例:

    8

很多人說沒看懂樣例,好心的我來告訴大家樣例是怎麼回事:
一開始全是BUG:X X X
只能用1補丁:X X O
然後用2:X O X
再用一次1:X O O
用3:O X X
又只能用1:O X O
再用2:O O X
最後再來一次1:O O O
完事


洛谷居然把這道題放在網絡流24題裏,真不知道它於網絡流的關係在何處,誤導?


經過隨便仔細地思考後,你會發現對於某一個狀態可以用的補丁是可以確定的,也就是說它之後可以變成的狀態我們是可以枚舉出來的,而且我們還知道轉移的代價,而且我們還知道初始狀態(全是BUG)和終止狀態(沒有BUG)

你有沒有想到什麼???
噢噢噢噢~~~~~~~~~~~~~~~~~~~~~~~~對對對!!!
(神馬玩意,我完全不知道……)

有沒有發現這是一個最短路問題!
這張圖的節點就是對於每個BUG有沒有修好所構成的2^n 個狀態,至於邊,就是某個狀態和能通過補丁轉移成的另一個狀態間有一條單向邊,而邊權就是修復的時間,注意哦,這些點,這些邊是不用真的建出來的,我們直接枚舉狀態之間的轉移,哈哈,最短路一搞,美滋滋(✿◕‿◕✿)
別高興太早了,你還需要考慮這2^n 個狀態以一種什麼方式保存下來——一定有大佬想到了:對於每個BUG都是修好和被修好兩個狀態,所以如果我們用1/0表示,就可以狀壓成一個數字,完美!現在可以高興了!!

啦啦啦,什麼,TLE!!!!!沒錯,畢竟人家有2 ^20 個點,而且它還是一個稠密圖。So,嚴重推薦使用堆優化Dijkstra
OK,完事


UVA658代碼:

#include<bits/stdc++.h>
#define inf 2000000000
using namespace std;

int n,m;
int dist[2000005],vis[2000005],w[105];
char c[105][25],r[105][25];

struct node{
	int d,u;
};

priority_queue<node> q;

bool operator < (node a,node b){
	return a.d>b.d;
}

int check(int u,int k){
	int o=u;
	for (int i=n-1;i>=0;i--){
		if (u%2==1 && c[k][i]=='-') return -1;
		if (u%2==0 && c[k][i]=='+') return -1;
		u>>=1;
	}
	int res=0;
	for (int i=n-1;i>=0;i--){
		if (r[k][i]=='+' || (r[k][i]=='0' && o%2==1)){
			res+=(1<<(n-i-1));
		}
		o>>=1;
	}
	return res;
}

void dijkstra(){
	memset(vis,0,sizeof(vis));
	for (int i=0;i<(1<<n);i++) dist[i]=inf;
	dist[(1<<n)-1]=0;
	q.push((node){0,(1<<n)-1});
	while(!q.empty()){
		int u=q.top().u;
		if (u==0) return;
		q.pop();
		if (vis[u]) continue;
		vis[u]=1;
		for (int i=0;i<m;i++){
			int v=check(u,i);
			if(v!=-1 && !vis[v] && dist[v]>dist[u]+w[i]){
				dist[v]=dist[u]+w[i];
				q.push((node){dist[v],v});
			}
		}
	}
}

int main(){
	int cas=0;
	scanf("%d%d",&n,&m);
	while(n!=0 || m!=0){
		while(!q.empty()) q.pop();
		for (int j=0;j<m;j++){
			scanf("%d",&w[j]);
			char ch;
			scanf("%c",&ch);
			for (int i=0;i<n;i++){
				scanf("%c",&c[j][i]);
			}
			scanf("%c",&ch);
			for (int i=0;i<n;i++){
				scanf("%c",&r[j][i]);
			}
			scanf("%c",&ch);
		}
		dijkstra();
		cout<<"Product "<<++cas<<endl;
		if (dist[0]==inf) cout<<"Bugs cannot be fixed."<<endl<<endl;
		else cout<<"Fastest sequence takes "<<dist[0]<<" seconds."<<endl<<endl;
		scanf("%d%d",&n,&m);
	}
	return 0;
} 

於HG機房

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章