ccf五年試題三年模擬

過幾天就要參加這個認證了,上週看了上把的題,雖然好久沒寫代碼了但是應該比上次打的時候強點,加油。
地鐵修建
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章