為了得到書法大家的真傳,小 e 同學下定決心去拜訪住在魔法森林中的隱 士。魔法森林可以被看成乙個包含 n 個節點 m 條邊的無向圖,節點標號為 1,2,3,…,n,邊標號為 1,2,3,…,m。初始時小 e 同學在 1 號節點,隱士則住在 n 號節點。小 e 需要通過這一片魔法森林,才能夠拜訪到隱士。
魔法森林中居住了一些妖怪。每當有人經過一條邊的時候,這條邊上的妖怪 就會對其發起攻擊。幸運的是,在 1 號節點住著兩種守護精靈:a 型守護精靈與 b 型守護精靈。小 e 可以借助它們的力量,達到自己的目的。
只要小 e 帶上足夠多的守護精靈,妖怪們就不會發起攻擊了。具體來說,無 向圖中的每一條邊 ei 包含兩個權值 ai 與 bi 。若身上攜帶的 a 型守護精靈個數不 少於 ai ,且 b 型守護精靈個數不少於 bi ,這條邊上的妖怪就不會對通過這條邊 的人發起攻擊。當且僅當通過這片魔法森林的過程中沒有任意一條邊的妖怪向 小 e 發起攻擊,他才能成功找到隱士。
由於攜帶守護精靈是一件非常麻煩的事,小 e 想要知道,要能夠成功拜訪到 隱士,最少需要攜帶守護精靈的總個數。守護精靈的總個數為 a 型守護精靈的 個數與 b 型守護精靈的個數之和。
輸入格式:
輸入檔案的第 1 行包含兩個整數 n,m,表示無向圖共有 n 個節點,m 條邊。 接下來 m 行,第i+ 1 行包含 4 個正整數 xi,yi,ai,bi,描述第i條無向邊。 其中xi與 yi為該邊兩個端點的標號,ai 與 bi 的含義如題所述。 注意資料中可能包含重邊與自環。
輸出格式:
輸出一行乙個整數:如果小 e 可以成功拜訪到隱士,輸出小 e 最少需要攜 帶的守護精靈的總個數;如果無論如何小 e 都無法拜訪到隱士,輸出「-1」(不 含引號)。
輸入樣例#1:複製
4 5輸出樣例#1:複製1 2 19 1
2 3 8 12
2 4 12 15
1 3 17 8
3 4 1 17
32輸入樣例#2:複製
3 1輸出樣例#2:複製1 2 1 1
-1如果小 e 走路徑 1→2→4,需要攜帶 19+15=34 個守護精靈; 如果小 e 走路徑 1→3→4,需要攜帶 17+17=34 個守護精靈; 如果小 e 走路徑 1→2→3→4,需要攜帶 19+17=36 個守護精靈; 如果小 e 走路徑 1→3→2→4,需要攜帶 17+15=32 個守護精靈。 綜上所述,小 e 最少需要攜帶 32 個守護精靈。
每條邊有兩個權值,合在一起維護十分不便,考慮將它們分開。
將所有邊按權值a從小到大排序,每一次加入一條邊,找一下1~n的所有路徑中權值b的最大值的最小值,然後用amax+bmax更新答案。
為什麼這樣做是對的呢,如果bmax所在的路徑並不是amax所在的路徑,那麼我們在放入amax之前,bmax就已經和乙個比amax要小的權值更新了答案,所以更優解已經被計算在內了。
然後每次spfa不需要memset,直接將當前加入的邊的兩端點入隊就好。
這道題沒有設計卡spfa的資料,所以spfa可以水過去。
1但是spfa的複雜度是無法保證的,如果考場上要穩過的話就需要乙個複雜度更加穩定的演算法。//never forget why you start
2 #include3 #include4 #include5 #include6 #include7 #include8 #include9
#define inf (2000000000)
10using
namespace
std;
11int n,m,ans=inf;
12 queuemem;
13struct
edgee[100005
];16
struct
nodeedge[200005
];19
int head[50005
],size;
20void putin(int
from,int to,int dis1,int
dis2)
28int dist[50005
];29
bool cmp(const edge a,const
edge b)
32int vis[50005
];33
void spfa(int x,int
y)48}49
}50}51
}52intmain()
67if(ans==707406379)printf("
-1\n");
68else printf("
%d\n
",ans);
69return0;
70 }
這題的正解是lct,思維難度還是很高的,首先我們將邊化為點,如果一條邊連線x和y兩個點,我們可以認為是乙個點分別和x,y兩點相連。這樣我們就可以將權值資訊放到中間那個點中。
然後還是考慮排序,先按權值a排序,從小到大加邊,每次加一條邊,就相當於是link一下x,再link一下y。
每次判斷1和n是否聯通,如果聯通,就找路徑上的最大值更新答案就好。
如果我們在連線的時候發現x和y是聯通的,如果我們直接聯通就會產生環,那麼我們考慮將這個環上最大的邊刪掉,因為乙個環上最大的邊是沒有存在的意義的。(當我們要經過這條最大的邊的時候,我們可以從環的另外一邊繞過去)
注意:我們要刪掉的是這個環上最大的邊,所以如果新加入的邊的權值比原路徑的最大值還要大,我們就沒有必要加入了。(在這裡被坑了好久)
1//never forget why you start
2 #include3 #include4 #include5 #include6 #include7 #include8
#define ll(x) lct[x].child[0]
9#define rr(x) lct[x].child[1]
10#define son(x,t) lct[x].child[t]
11#define inf (2147483647)
12using
namespace
std;
13int n,m,ans=inf;
14int
read()
17while(i>='
0'&&i<='9')
18return ans*f;19}
20struct
edge
25 }e[100005
];26
struct
lctlct[200005
];30
void push_up(int
x)37
void push_rev(int
x)42
void push_down(int
x)48}49
void push(int
x)53
int getson(int
x)56
void rotate(int
x)67
void splay(int
x)73
void access(int
x)while
(x);82}
83void mroot(int
x)88
void link(int u,int
v)92
void cut(int u,int
v)100
struct
fa107
int find(int
x)111
void merge(int x,int
y)117
}118
bool judge(int x,int
y)122
}fa;
123int ppos[200005
];124
intmain()
134for(i=1;i<=m;i++)
140 sort(e+1,e+m+1
);141
for(i=1;i<=m;i++)ppos[e[i].id]=i;
142for(i=1;i<=m;i++)
156}
157if(flag||!fa.judge(u,v))
163if(fa.judge(1
,n))
169}
170if(ans==inf)printf("
-1\n");
171else printf("
%d\n
",ans);
172return0;
173 }
NOI2014 魔法森林
為了得到書法大家的真傳,小e同學下定決心去拜訪住在魔法森林中的隱士。魔法森林可以被看成乙個包含個n節點m條邊的無向圖,節點標號為 1 n 邊標號為1 m 初始時小e同學在 1 號節點,隱士則住在 n 號節點。小e需要通過這一片魔法森林,才能夠拜訪到隱士。魔法森林中居住了一些妖怪。每當有人經過一條邊的...
NOI2014 魔法森林
為了得到書法大家的真傳,小 e 同學下定決心去拜訪住在魔法森林中的隱士。魔法森林可以被看成乙個包含 n 個節點 m 條邊的無向圖,節點標號為1,2,3,n,邊標號為 1,2,3,m。初始時小 e 同學在 1 號節點,隱士則住在 n 號節點。小 e 需要通過這一片魔法森林,才能夠拜訪到隱士。魔法森林中...
NOI2014 魔法森林
noi2014 魔法森林 要求a 與 b 的總和最小 可以按a排序 再以b為權值維護一顆樹 lct維護最小生成樹 要解決的問題 將每一條邊變為乙個點 邊權變為點權 舉個栗子 u v有一條邊權為w的邊 怎lct連邊方式為 u new v new的點權為w 不斷維護最小生成樹 如果新加入的邊的 u與v不...