1. 程式人生 > 其它 >【一本通 1488:新的開始】題解

【一本通 1488:新的開始】題解

題目連結

題目

發展採礦業當然首先得有礦井,小 FF 花了上次探險獲得的千分之一的財富請人在島上挖了 \(n\) 口礦井,但他似乎忘記考慮的礦井供電問題……

為了保證電力的供應,小 FF 想到了兩種辦法:

在這一口礦井上建立一個發電站,費用為 \(v\)(發電站的輸出功率可以供給任意多個礦井)。

將這口礦井與另外的已經有電力供應的礦井之間建立電網,費用為 \(p\)

小 FF 希望身為「NewBe_One」計劃首席工程師的你幫他想出一個保證所有礦井電力供應的最小花費。

思路

\(a_i\) 代表當前此點的最小代價,則開始\(a_i=v_i\)

然後我們進行 \(n\) 次來逐個點確定

其代價,假設第 \(j\) 次確立的點為 \(k\),需滿足 \(k\) 之前未確立且是剩餘點中 \(a_k\) 最小

然後對於此時答案 \(ans\),我們讓其加上 \(a_k\),之後對所有未確定\(a\) 進行更新,例如對於剩餘的某個點 \(i\),有 \(a_i=\min(a_i,\; p_{k,i})\)

上述過程均可暴力實現,複雜度為 \(O(n^2)\)

程式碼

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define mo
#define N 310
//#define M
int n, m, i, j, k; 
int v[N], b[N], a[N], p[N][N], ans; 

signed main()
{
//	freopen("tiaoshi.in","r",stdin);
//	freopen("tiaoshi.out","w",stdout);
	n=read(); a[k=0]=1e9; 
	for(i=1; i<=n; ++i) 
		v[i]=a[i]=read(); 
	for(i=1; i<=n; ++i)
		for(j=1; j<=n; ++j) 
			p[i][j]=read(); 
	for(i=1; i<=n; ++i)
	{
		for(j=1, k=0; j<=n; ++j)
			if(!b[j] && a[j]<a[k]) k=j; 
		for(j=b[k]=1, ans+=a[k]; j<=n; ++j)
			if(!b[j]) a[j]=min(a[j], p[k][j]); 
	}
	printf("%lld", ans); 
	return 0;
}

總結

此類題目算是思維題,對於每個位置代價不確定時,可以考慮逐個確定。

可以考慮貪心思想,有點類似DijPrim,先對代價最小的點進行處理,然後更新其他點,再繼續進行處理。

有些題目可能要加上堆優化