過幾天就要參加這個認證了,上週看了上把的題,雖然好久沒寫代碼了但是應該比上次打的時候強點,加油。
地鐵修建
201703-4
問題描述
試題編號: 201703-4
試題名稱: 地鐵修建
時間限制: 1.0s
內存限制: 256.0MB
問題描述:
問題描述
A市有n個交通樞紐,其中1號和n號非常重要,爲了加強運輸能力,A市決定在1號到n號樞紐間修建一條地鐵。
地鐵由很多段隧道組成,每段隧道連接兩個交通樞紐。經過勘探,有m段隧道作爲候選,兩個交通樞紐之間最多隻有一條候選的隧道,沒有隧道兩端連接着同一個交通樞紐。
現在有n家隧道施工的公司,每段候選的隧道只能由一個公司施工,每家公司施工需要的天數一致。而每家公司最多隻能修建一條候選隧道。所有公司同時開始施工。
作爲項目負責人,你獲得了候選隧道的信息,現在你可以按自己的想法選擇一部分隧道進行施工,請問修建整條地鐵最少需要多少天。
輸入格式
輸入的第一行包含兩個整數n, m,用一個空格分隔,分別表示交通樞紐的數量和候選隧道的數量。
第2行到第m+1行,每行包含三個整數a, b, c,表示樞紐a和樞紐b之間可以修建一條隧道,需要的時間爲c天。
輸出格式
輸出一個整數,修建整條地鐵線路最少需要的天數。
樣例輸入
6 6
1 2 4
2 3 4
3 6 7
1 4 2
4 5 5
5 6 6
樣例輸出
6
樣例說明
可以修建的線路有兩種。
第一種經過的樞紐依次爲1, 2, 3, 6,所需要的時間分別是4, 4, 7,則整條地鐵線需要7天修完;
第二種經過的樞紐依次爲1, 4, 5, 6,所需要的時間分別是2, 5, 6,則整條地鐵線需要6天修完。
第二種方案所用的天數更少。
評測用例規模與約定
對於20%的評測用例,1 ≤ n ≤ 10,1 ≤ m ≤ 20;
對於40%的評測用例,1 ≤ n ≤ 100,1 ≤ m ≤ 1000;
對於60%的評測用例,1 ≤ n ≤ 1000,1 ≤ m ≤ 10000,1 ≤ c ≤ 1000;
對於80%的評測用例,1 ≤ n ≤ 10000,1 ≤ m ≤ 100000;
對於100%的評測用例,1 ≤ n ≤ 100000,1 ≤ m ≤ 200000,1 ≤ a, b ≤ n,1 ≤ c ≤ 1000000。
所有評測用例保證在所有候選隧道都修通時1號樞紐可以通過隧道到達其他所有樞紐。
用dij或者kru,spfa都可以。
用spfa最短路,改d數組,d數組本來的意思是 d_i 從源點到i點最小花費。改成 從原點到 d_i點最大單邊。 我當時就是這裏寫的有點問題。所以纔給了40.
用kruskal的思想,把邊排序後,放m-1個單邊,使之不成環(其實就是判斷一下當前加入邊他們倆點的爸爸是不是一個爸爸。),放好之後維護一個最大值。可以證明,1-m最大邊最小的那個一定在這裏。
考試匆忙,等有時間在想具體證明,畢竟次小我都忘記了。。
#include <iostream>
#include <cstring>
#include <queue>
#include <cstdio>
using namespace std;
/* 用dij寫一遍?
我開始寫的是d數組維護的是
距離d數組越遠越好。
這是肯定不會對的。
只是過了一部分樣例而已。
*/
const int maxn=2e5+4;
int head[maxn];
struct Node{
int to,next,value;
}node[maxn*2];
int len;
void init(){
memset(head,-1,sizeof(head));
len=0;
}
void add(int a,int b,int c){
node[len].to=b;
node[len].value=c;
node[len].next=head[a];
head[a]=len++;
}
int d[maxn];
int rel[maxn];
int m,n;
bool vis[maxn];
void spfa(){
queue<int>q;
for(int i=0;i<=n;i++){
d[i]=1e9;
}
memset(vis,false,sizeof(vis));
memset(rel,0,sizeof(rel));
while(!q.empty()) q.pop();
q.push(1);
vis[1]=true;
d[1]=0;
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=node[i].next){
int to=node[i].to;
int cost=node[i].value;
if(d[to]>max(cost,d[u])){
d[to]=max(cost,d[u]);
if(!vis[to]){
vis[to]=true;
q.push(to);
}
}
}
}
}
int main()
{ int a,b,c;
scanf("%d%d",&m,&n);
init();
for(int i=0;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
spfa();
printf("%d\n",d[m]);
return 0;
}
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
using namespace std;
/* 也可以用mst來做。
用spfa算法是可以想到的,也比較直觀。
因爲d數組正常情況下是存的 從目標點到當前點的總距離。
我們維護的是 最小的邊的距離。
用kruskal算法的話,是直接找前 m-1個邊xjb鼓搗,只要他們不成邊就行。
這個是類似的,當1和m聯通之後就結束。並且結果一定是。
注意1 邊數不一定是m-1。只是以連通性來確定的。
如果用dfs寫的話,是虧的,因爲我們不能保證這一結果。
*/
const int maxn=1e5+10;
struct edge{
int from,to,value;
edge(int a,int b,int c){
from=a;
to=b;
value=c;
}
};
vector<edge>v;
bool cmp(edge a,edge b){
return a.value<b.value;
}
int fa[maxn];
int find2(int a){
if(a==fa[a]) return a;
return fa[a]=find2(fa[a]);
}
int m,n;
void solve(){
sort(v.begin(),v.end(),cmp);
int rel=-1;
for(int i=0;i<=m;i++) fa[i]=i;
/*for(int i=0;i<v.size();i++){
cout<<v[i].value<<"??"<<endl;
}*/
for(int i=0;i<v.size();i++){
int x=find2(1);
int y=find2(m);
//cout<<"xialaide"<<x<<" "<<y<<endl;
if(x==y)break;
int x2=find2(v[i].from);
int y2=find2(v[i].to);
if(x2==y2)continue;
fa[y2]=x2;
rel=max(rel,v[i].value);
}
printf("%d\n",rel);
}
int main()
{ int a,b,c;
scanf("%d%d",&m,&n);
v.clear();
for(int i=0;i<n;i++){
scanf("%d%d%d",&a,&b,&c);
v.push_back(edge(a,b,c));
}
solve();
return 0;
}
問題描述
試題編號: 201709-4
試題名稱: 通信網絡
時間限制: 1.0s
內存限制: 256.0MB
問題描述:
問題描述
某國的軍隊由N個部門組成,爲了提高安全性,部門之間建立了M條通路,每條通路只能單向傳遞信息,即一條從部門a到部門b的通路只能由a向b傳遞信息。信息可以通過中轉的方式進行傳遞,即如果a能將信息傳遞到b,b又能將信息傳遞到c,則a能將信息傳遞到c。一條信息可能通過多次中轉最終到達目的地。
由於保密工作做得很好,並不是所有部門之間都互相知道彼此的存在。只有當兩個部門之間可以直接或間接傳遞信息時,他們才彼此知道對方的存在。部門之間不會把自己知道哪些部門告訴其他部門。
上圖中給了一個4個部門的例子,圖中的單向邊表示通路。部門1可以將消息發送給所有部門,部門4可以接收所有部門的消息,所以部門1和部門4知道所有其他部門的存在。部門2和部門3之間沒有任何方式可以發送消息,所以部門2和部門3互相不知道彼此的存在。
現在請問,有多少個部門知道所有N個部門的存在。或者說,有多少個部門所知道的部門數量(包括自己)正好是N。
輸入格式
輸入的第一行包含兩個整數N, M,分別表示部門的數量和單向通路的數量。所有部門從1到N標號。
接下來M行,每行兩個整數a, b,表示部門a到部門b有一條單向通路。
輸出格式
輸出一行,包含一個整數,表示答案。
樣例輸入
4 4
1 2
1 3
2 4
3 4
樣例輸出
2
樣例說明
部門1和部門4知道所有其他部門的存在。
評測用例規模與約定
對於30%的評測用例,1 ≤ N ≤ 10,1 ≤ M ≤ 20;
對於60%的評測用例,1 ≤ N ≤ 100,1 ≤ M ≤ 1000;
對於100%的評測用例,1 ≤ N ≤ 1000,1 ≤ M ≤ 10000。
這題就有點衰了,我題意有點矇蔽,以爲一個點要麼是全正向接受,要麼全反向接受,那麼做兩個圖,然後找到入度爲0點搜索? 一分沒得。
去掉入度爲0條件,得35,應該是超時,
看了別人的代碼,還是不錯的,搜索(n*(m+n)) 1e7,一秒還可以。附上錯的代碼,有時間想怎麼優化把。
1 35分代碼
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <set>
using namespace std;
/*找根,暴力搜索
*/
const int maxn=1e5;
vector<int>g[maxn];
vector<int>G[maxn];
int du[maxn];
int du2[maxn];
bool vis[maxn];
set<int>s;
int m;
int solve(int x){
queue<int>q;
q.push(x);
int num=0;
memset(vis,false,sizeof(vis));
vis[x]=true;
num++;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<g[u].size();i++){
int to=g[u][i];
if(!vis[to]){
vis[to]=true;
num++;
q.push(to);
}
}
}
if(num==m)return 1;
return 0;
}
// 下一個處理
int solve2(int x){
queue<int>q;
q.push(x);
int num=0;
memset(vis,false,sizeof(vis));
vis[x]=true;
num++;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<G[u].size();i++){
int to=G[u][i];
if(!vis[to]){
vis[to]=true;
num++;
q.push(to);
}
}
}
if(num==m)return 1;
return 0;
}
int main()
{ int n,a,b;
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++){
scanf("%d%d",&a,&b);
g[a].push_back(b);
du[b]++;
G[b].push_back(a);
du2[a]++;
}
int ans=0;
for(int i=1;i<=m;i++){
//if(du[i]==0){
if(solve(i)==1)
ans++,s.insert(i);
//}
}
for(int i=1;i<=m;i++){
//if(du2[i]==0){
if(solve2(i)==1){
ans++,s.insert(i);
}
//}
}
printf("%d\n",(int)(s.size()));
return 0;
}
參考的別人代碼(不用百度了 前幾個都是這樣寫的,)
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <cstring>
#include <set>
using namespace std;
/*找根,暴力搜索
*/
const int maxn=1e3+2;
vector<int>g[maxn];
bool vis[maxn];
int mp[maxn][maxn];
void dfs(int a,int b){
mp[b][a]=1;
mp[a][b]=1;
for(int i=0;i<g[a].size();i++){
if(!vis[g[a][i]]){
vis[g[a][i]]=true;
dfs(g[a][i],b);
}
}
}
int main()
{ int n,m,a,b;
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++){
scanf("%d%d",&a,&b);
g[a].push_back(b);
}
for(int i=1;i<=m;i++){
memset(vis,false,sizeof(vis));
dfs(i,i);
}
int sum=0;
int ans=0;
for(int i=1;i<=m;i++){
sum=0;
for(int j=1;j<=m;j++){
sum+=mp[i][j];
}
if(sum==m)ans++;
}
printf("%d\n",ans);
return 0;
}
201709-2
問題描述
試題編號: 201709-2
試題名稱: 公共鑰匙盒
時間限制: 1.0s
內存限制: 256.0MB
問題描述:
問題描述
有一個學校的老師共用N個教室,按照規定,所有的鑰匙都必須放在公共鑰匙盒裏,老師不能帶鑰匙回家。每次老師上課前,都從公共鑰匙盒裏找到自己上課的教室的鑰匙去開門,上完課後,再將鑰匙放回到鑰匙盒中。
鑰匙盒一共有N個掛鉤,從左到右排成一排,用來掛N個教室的鑰匙。一串鑰匙沒有固定的懸掛位置,但鑰匙上有標識,所以老師們不會弄混鑰匙。
每次取鑰匙的時候,老師們都會找到自己所需要的鑰匙將其取走,而不會移動其他鑰匙。每次還鑰匙的時候,還鑰匙的老師會找到最左邊的空的掛鉤,將鑰匙掛在這個掛鉤上。如果有多位老師還鑰匙,則他們按鑰匙編號從小到大的順序還。如果同一時刻既有老師還鑰匙又有老師取鑰匙,則老師們會先將鑰匙全還回去再取出。
今天開始的時候鑰匙是按編號從小到大的順序放在鑰匙盒裏的。有K位老師要上課,給出每位老師所需要的鑰匙、開始上課的時間和上課的時長,假設下課時間就是還鑰匙時間,請問最終鑰匙盒裏面鑰匙的順序是怎樣的?
輸入格式
輸入的第一行包含兩個整數N, K。
接下來K行,每行三個整數w, s, c,分別表示一位老師要使用的鑰匙編號、開始上課的時間和上課的時長。可能有多位老師使用同一把鑰匙,但是老師使用鑰匙的時間不會重疊。
保證輸入數據滿足輸入格式,你不用檢查數據合法性。
輸出格式
輸出一行,包含N個整數,相鄰整數間用一個空格分隔,依次表示每個掛鉤上掛的鑰匙編號。
樣例輸入
5 2
4 3 3
2 2 7
樣例輸出
1 4 3 2 5
樣例說明
第一位老師從時刻3開始使用4號教室的鑰匙,使用3單位時間,所以在時刻6還鑰匙。第二位老師從時刻2開始使用鑰匙,使用7單位時間,所以在時刻9還鑰匙。
每個關鍵時刻後的鑰匙狀態如下(X表示空):
時刻2後爲1X345;
時刻3後爲1X3X5;
時刻6後爲143X5;
時刻9後爲14325。
樣例輸入
5 7
1 1 14
3 3 12
1 15 12
2 7 20
3 18 12
4 21 19
5 30 9
樣例輸出
1 2 3 5 4
評測用例規模與約定
對於30%的評測用例,1 ≤ N, K ≤ 10, 1 ≤ w ≤ N, 1 ≤ s, c ≤ 30;
對於60%的評測用例,1 ≤ N, K ≤ 50,1 ≤ w ≤ N,1 ≤ s ≤ 300,1 ≤ c ≤ 50;
對於所有評測用例,1 ≤ N, K ≤ 1000,1 ≤ w ≤ N,1 ≤ s ≤ 10000,1 ≤ c ≤ 100。
水題,然而還是調了一下,是先放在拿,不然出bug
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
/*
violence
*/
const int maxn=1e3+2;
vector<pair<int,pair<int,int> > >q;
int a[maxn];
bool cmp2(pair<int,pair<int,int> >a,pair<int,pair<int,int> >b){
return a.first<b.first;
}
int main()
{ int m,n,a1,b,c;
scanf("%d%d",&m,&n);
int tim=0;
while(n--){
scanf("%d%d%d",&a1,&b,&c);
c=b+c;
q.push_back(make_pair(a1,make_pair(b,c)));
tim=max(c,tim);
}
//cout<<tim<<endl;
sort(q.begin(),q.end(),cmp2);
for(int i=1;i<=m;i++){
a[i]=i;
}
for(int i=1;i<=tim;i++){
for(int j=0;j<q.size();j++){
if(q[j].second.second==i){
for(int x=1;x<=m;x++){
if(a[x]==0){
a[x]=q[j].first;
break;
}
}
}
}
for(int j=0;j<q.size();j++){
if(q[j].second.first==i){
for(int x=1;x<=m;x++){
if(a[x]==q[j].first){
a[x]=0;break;
}
}
}
}
/*for(int i=1;i<=m;i++){
if(i!=1){
putchar(' ');
}
printf("%d",a[i]);
}
cout<<" "<<i<<endl;
cout<<endl;*/
}
for(int i=1;i<=m;i++){
if(i!=1){
putchar(' ');
}
printf("%d",a[i]);
}
cout<<endl;
return 0;
}