程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> BZOJ[Sdoi2010]大陸爭霸 最短路變形

BZOJ[Sdoi2010]大陸爭霸 最短路變形

編輯:C++入門知識

Description

在一個遙遠的世界裡有兩個國家:位於大陸西端的傑森國和位於大陸東端的 克裡斯國。兩個國家的人民分別信仰兩個對立的神:傑森國信仰象征黑暗和毀滅 的神曾·布拉澤,而克裡斯國信仰象征光明和永恆的神斯普林·布拉澤。 幻想歷 8012年 1月,傑森國正式宣布曾·布拉澤是他們唯一信仰的神,同 時開始迫害在傑森國的信仰斯普林·布拉澤的克裡斯國教徒。 幻想歷 8012年 3月2日,位於傑森國東部小鎮神谕鎮的克裡斯國教徒發動 起義。 幻想歷 8012年 3月7日,神谕鎮的起義被傑森國大軍以殘酷手段鎮壓。 幻想歷 8012年 3月8日,克裡斯國對傑森國宣戰。由數十萬大軍組成的克 裡斯軍團開至兩國邊境,與傑森軍團對峙。 幻想歷 8012年 4月,克裡斯軍團攻破傑森軍團防線進入神谕鎮,該鎮幸存 的克裡斯國教徒得到解放。 戰爭隨後進入膠著狀態,曠日持久。戰況慘烈,一時間槍林彈雨,硝煙彌漫, 民不聊生。 幻想歷 8012年 5月12日深夜,斯普林·布拉澤降下神谕:“Trust me, earn eternal life.”克裡斯軍團士氣大增。作為克裡斯軍團的主帥,你決定利用這一機 會發動奇襲,一舉擊敗傑森國。具體地說,傑森國有 N 個城市,由 M條單向道 路連接。神谕鎮是城市 1而傑森國的首都是城市 N。你只需摧毀位於傑森國首都 的曾·布拉澤大神殿,傑森國的信仰,軍隊還有一切就都會土崩瓦解,灰飛煙滅。 為了盡量減小己方的消耗,你決定使用自爆機器人完成這一任務。唯一的困 難是,傑森國的一部分城市有結界保護,不破壞掉結界就無法進入城市。而每個 城市的結界都是由分布在其他城市中的一些結界發生器維持的,如果想進入某個 城市,你就必須破壞掉維持這個城市結界的所有結界發生器。 現在你有無限多的自爆機器人,一旦進入了某個城市,自爆機器人可以瞬間 引爆,破壞一個目標(結界發生器,或是傑森國大神殿),當然機器人本身也會 一起被破壞。你需要知道:摧毀傑森國所需的最短時間。

Input

第一行兩個正整數 N, M。 接下來 M行,每行三個正整數 ui, vi, wi,表示有一條從城市ui到城市 vi的單 向道路,自爆機器人通過這條道路需要 wi的時間。 之後 N 行,每行描述一個城市。首先是一個正整數 li,維持這個城市結界所 使用的結界發生器數目。之後li個1~N 之間的城市編號,表示每個結界發生器的 位置。如果 Li = 0,則說明該城市沒有結界保護,保證L1 = 0 。

Output

僅包含一個正整數 ,擊敗傑森國所需的最短時間。

Sample Input

6 6
1 2 1
1 4 3
2 3 1
2 5 2
4 6 2
5 3 2
0
0
0
1 3
0
2 3 5

Sample Output

5

\

HINT

對於 20%的數據,滿足 N≤15,M≤50;
對於 50%的數據,滿足 N≤500,M≤6,000;
對於 100%的數據,滿足 N≤3,000,M≤70,000,1≤wi≤108

輸入數據保證一定有解,且不會存在維持某個城市結界的結界發生器在這個
城市內部。
連接兩個城市的道路可能不止一條, 也可能存在一個城市自己到自己的道路。<喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vcD4KCjxicj4KPC9oMj4KPGJyPgoKPGJyPgoK1eK1wMziysfSu7XAtPjP3tbGtcTX7rbMwrfOyszio6zK18/I0OjSqrTdu9m52M+1zby1xMjrsd+21NOmtcS147LFxNy1vcv7o6zG5LTOv8nS1M2syrHX37bguPa146GjCsrXz8i/vMLHzqy7pMG9uPbK/dfpo6zSu7j2ysfU3cfSsru/vMLHtbHHsLXjtcTI67HftcTX7rbMvuDA62hbXaOs0ru49srH1ebKtbXEvuDA62Rpc1tdo6y/vMLH08NzcGZh1/ajrMO/tM64/NDCwcvSu7j2tePV5sq1tcTX7rbMvuDA66Osvs29q8v7vNPI67bTwdCjrL+0yse38cTcuPzQwsbky/u1xLXjo6y21NPaw7/Su7TOuPzQwqOstrzSqsmo0rux6b+0y/vL+dPQx7DH/bXE1+62zL7gwOujrMv50tTKsbzkuLTU07bIvs3Kx08oTl4zKdfz09Khowo8YnI+Cgo8cHJlIGNsYXNzPQ=="brush:java;">#include #include #include #include #include #include using namespace std; int get_int(){ int x=0;char c;int t=0; for (c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar()); if (c=='-'){t=1;c=getchar();} for (;c>='0'&&c<='9';c=getchar()){x*=10;x+=c-48;} if (t) x=-x;return x; } const int maxn=3050,maxm=70050; int n,m; long long inf; int heap[maxn][maxn],tal[maxn]; int stay[maxn]; long long d[maxn],f[maxn]; int first[maxn],to[maxm],next[maxm],w[maxm],size; void put(int x,int y,int ww) { size++; next[size]=first[x]; first[x]=size; to[size]=y; w[size]=ww; } int first_[maxn],to_[maxn*maxn/2],next_[maxn*maxn/2]; void put_(int x,int y) { size++; next_[size]=first_[x]; first_[x]=size; to_[size]=y; } void init() { inf=(1<<29); inf=inf*inf; n=get_int(),m=get_int(); for (int i=1;i<=n;i++) f[i]=d[i]=inf; d[1]=0; f[1]=0; for (int i=1;i<=m;i++) { int x=get_int(),y=get_int(),ww=get_int(); if (x!=y) put(x,y,ww); } size=0; for (int i=1;i<=n;i++) { for (int j=1;j<=n;j++) stay[j]=0; for (int j=get_int();j;j--) {int x=get_int(); if (!stay[x]); { tal[i]++; heap[i][tal[i]]=x; stay[x]=1; //up(i,tal[i]); put_(x,i); } } } } int line[maxn*5],mod=maxn*5-50; bool upmin(long long &x,long long y) { if (yx) {x=y;return true;} return false; } bool ban(int v) { long long ans=f[v]; f[v]=d[v]; for (int i=1;i<=tal[v];i++) upmax(f[v],f[heap[v][i]]); //printf("ans = %I64d f[%d] =%I64d\n",ans,v,f[v]); if (f[v]mod) tou=1; for (int k=first[line[tou]];k;k=next[k]) { upmin(d[to[k]],f[line[tou]]+w[k]); if (ban(to[k])) {//printf(" ok ban %d\n",to[k]); if (!stay[to[k]]) { // printf(" ok %d\n",to[k]); wei++; if (wei>mod) wei=1; line[wei]=to[k]; stay[to[k]]=1; } } } for (int k=first_[line[tou]];k;k=next_[k]) {//printf("try ban %d\n",to_[k]); if (ban(to_[k])) {//printf(" ok ban %d\n",to[k]); if (!stay[to_[k]]) { //printf(" ok %d\n",to[k]); wei++; if (wei>mod) wei=1; line[wei]=to_[k]; stay[to_[k]]=1; } } } stay[line[tou]]=0; // printf("tou = %d wei =%d\n",tou,wei); // for (int i=tou;i<=wei;i++) // printf("%d ",line[i]);printf("\n"); // for (int i=1;i<=n;i++) // printf("d[%d]=%I64d f[%d]=%I64d\n",i,d[i],i,f[i]); // printf("\n"); } printf("%I64d\n",f[n]); } int main() { freopen("landcraft.in","r",stdin); freopen("landcraft.out","w",stdout); init(); spfa(); }
換個方法,用dijstra考慮呢? 每次找當前能找到的最小值,用它來進行更新,遇到max就取max,遇到min就取min,有人會說,這肯定回wa完三。 其實不然。 我們這樣看,既然每次取得是最小值,那麼用來更新的一定是遞增的,所以對於一個點的限制只用考慮他最後一個max就夠了,然後再看這個點i的dis最大的前驅到這個點這一段,我們發現,他每次只會取min,而這些用來更新的點的dis已經大於了dis[i的最大的前驅],所以取min不影響,所以總的來說,他就是個dijstra模型加一句帶限制的更新。

#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
int n,m;
int tot=0;
int fir[200000],en[200000],nex[200000];
LL w[200000];
void ins(int a,int b,LL c){
	nex[++tot]=fir[a];
	fir[a]=tot;
	en[tot]=b;
	w[tot]=c;
}
int tot_=0;
int fir_[200000],en_[200000],nex_[200000];
void ins_(int a,int b){
	nex_[++tot_]=fir_[a];
	fir_[a]=tot_;
	en_[tot_]=b;
}
LL dis[200000];
int rd[200000];
bool flag[200000];
int main(){
//	freopen("landcraft.in","r",stdin);
//	freopen("landcraft.out","w",stdout);
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		ins(a,b,c);
		}
	for (int i=1;i<=n;i++){
		scanf("%d",&rd[i]);
		for (int j=1;j<=rd[i];j++){
			int x;
			scanf("%d",&x);
			ins_(x,i);
			}
		}
	for (int i=0;i<=n;i++) dis[i]=99999999ll;
	dis[1]=0;
	for (int i=1;i<=n;i++){
		int t=0;
		for (int j=1;j<=n;j++)
			if (!rd[j]&&flag[j]==false&&dis[j]

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved