# Graph# Dijkstra# Bitmasking# Greedy

e760 - 658 - It's not a Bug, it's a Feature!

🔗 前往 ZeroJudge 原題

題目描述

題目描述了修復 bug 的問題。有 n 個 bug 和 m 個補丁。每個補丁需要一定的時間來安裝,並且可能依賴於其他 bug 的存在或不存在,同時安裝補丁也可能引起或修復其他 bug。目標是找到修復所有 bug 的最少時間。

解題思路

這題可以建模為一個圖論問題。每個 bug 的狀態(存在或不存在)可以用一個位元表示,因此總共有 2^n 個狀態。圖的節點代表 bug 的狀態,邊代表安裝一個補丁的操作。邊的權重是安裝補丁所需的時間。

使用 Dijkstra 演算法來尋找從所有 bug 都存在(狀態為 2^n - 1)到所有 bug 都消失(狀態為 0)的最短路徑。

cnt 函數檢查是否可以安裝某個補丁,即檢查補丁的依賴條件是否滿足。 tran 函數模擬安裝補丁後 bug 狀態的變化。 djsk 函數實現 Dijkstra 演算法。

複雜度分析

  • 時間複雜度: O(2^n * m)。Dijkstra 演算法的時間複雜度通常是 O(E log V),其中 V 是節點數,E 是邊數。在這裡,V = 2^n,E = 2^n * m。
  • 空間複雜度: O(2^n)。需要一個大小為 2^n 的陣列 dis 來儲存每個狀態的最短距離。

程式碼

#include <bits/stdc++.h>
using namespace std;
int dis[1<<20],n,m,ca;
bool has[1<<20];
struct bd{
	int tm;
	string nd,gt;
};
bd a[105];
bool cnt(int id,int v){
	for(int i=0;i<n;++i){
		int k=v%2;
		if((a[id].nd[i]=='+'&&k==0)||(a[id].nd[i]=='-'&&k==1))return 0;
		v/=2;	
	}
	return 1;
}
int tran(int id,int v){
	string rt;
	int rtv=0;
	for(int i=0;i<n;++i){
		int k=v%2;
		if(a[id].gt[i]=='+')k=1;
		else if(a[id].gt[i]=='-')k=0;
		rt+=(k+'0');
		v/=2;	
	}
	for(int i=n-1;i>=0;--i){
		rtv*=2;
		rtv+=rt[i]-'0';
	}
	return rtv;
}
void djsk(int bst){
	queue <pair <int,int>> pq;//dis v
	pq.push({0,bst});
	dis[bst]=0;
	while(!pq.empty()){
		int ft=pq.front().first,sec=pq.front().second;
		pq.pop();
		for(int i=0;i<m;++i){
			if(cnt(i,sec)){
				int tt=tran(i,sec);
				if(dis[tt]>dis[sec]+a[i].tm){
					dis[tt]=dis[sec]+a[i].tm;
					pq.push({dis[tt],tt});
				}
			}
		}
	}
	return;
}
int main(){
	cin.tie(0); ios::sync_with_stdio(false);
	while(cin >> n >> m){
		if(n+m==0)break;
		memset(has,0,sizeof(has));
		for(int i=0;i<(1<<n);++i)dis[i]=1e9;
		for(int i=0;i<m;++i)cin >> a[i].tm >> a[i].nd >> a[i].gt;
		djsk((1<<n)-1);
		cout << "Product " << ++ca << "\n";
		(dis[0]>=1e9)?cout << "Bugs cannot be fixed.\n":cout << "Fastest sequence takes " << dis[0] << " seconds.\n";
		cout << "\n";
	}
}

Discussion