1. 程式人生 > >2017 09 17 測驗解題報告

2017 09 17 測驗解題報告

con std for tdi 有一個 簡單 網格 檢驗 ffffff

預計分數 100+100+20 >=220

實際分數 100+50+20 =170

T1 :100

巧克力棒(chocolate)
Time Limit:1000ms Memory Limit:64MB
題目描述
LYK 找到了一根巧克力棒,但是這根巧克力棒太長了,LYK 無法一口吞進去。
具體地,這根巧克力棒長為 n,它想將這根巧克力棒折成 n 段長為 1 的巧克力棒,然後
慢慢享用。
它打算每次將一根長為 k 的巧克力棒折成兩段長為 a 和 b 的巧克力棒,此時若 a=b,則
LYK 覺得它完成了一件非常困難的事,並會得到 1 點成就感。
LYK 想知道一根長度為 n 的巧克力棒能使它得到最多幾點成就感。

輸入格式(chocolate.in)
第一行一個數 n。
輸出格式(chocolate.out)
一個數表示答案。
輸入樣例
7
輸出樣例
4
數據範圍
對於 20%的數據 n<=5。
對於 50%的數據 n<=20。
對於 80%的數據 n<=2000。
對於 100%的數據 n<=1000000000。
樣例解釋
將 7 掰成 3+4, 將 3 掰成 1+2, 將 4 掰成 2+2 獲得 1 點成就感, 將剩下的所有 2 掰成 1+1
獲得 3 點成就感。總共 4 點成就感。

把一段長度為n的(n為2的冪次方)巧克力二分可以切n-1次,每次用二的冪次方數對區間進行切割,

遞歸到長度為1或0(此時無法再切)統計長度

#include<cstdio>
int n;
int dfs(int sum)
{
    if(sum==1||sum==0)return 0;
    int cnt=1;
    while(cnt*2<=sum) cnt*=2;
    return cnt-1+dfs(sum-cnt);
}
int main(){    
    freopen("chocolate.in","r",stdin);
    freopen("chocolate.out","w",stdout);
    scanf("%d",&n);
    printf(
"%d\n",dfs(n)); return 0; }

T2 :50

錯因:隊列數組開小應為1000*1000,實為1000

LYK 快跑!(run)
Time Limit:5000ms Memory Limit:64MB
題目描述
LYK 陷進了一個迷宮! 這個迷宮是網格圖形狀的。 LYK 一開始在(1,1)位置, 出口在(n,m)。
而且這個迷宮裏有很多怪獸,若第 a 行第 b 列有一個怪獸,且此時 LYK 處於第 c 行 d 列,此
時這個怪獸對它的威脅程度為|a-c|+|b-d|。
LYK 想找到一條路徑,使得它能從(1,1)到達(n,m),且在途中對它威脅程度最小的怪獸的
威脅程度盡可能大。
當然若起點或者終點處有怪獸時,無論路徑長什麽樣,威脅程度最小的怪獸始終=0。
輸入格式(run.in)
第一行兩個數 n,m。
接下來 n 行,每行 m 個數,如果該數為 0,則表示該位置沒有怪獸,否則存在怪獸。
數據保證至少存在一個怪獸。
輸入格式(run.out)
一個數表示答案。
輸入樣例
3 4
0 1 1 0
0 0 0 0
1 1 1 0
輸出樣例
1
數據範圍
對於 20%的數據 n=1。
對於 40%的數據 n<=2。
對於 60%的數據 n,m<=10。
對於 80%的數據 n,m<=100。
對於 90%的數據 n,m<=1000。
對於另外 10%的數據 n,m<=1000 且怪獸數量<=100。

bfs處理出每個點與距離最近怪獸的距離,二分答案,二分路徑上的最小值用bfs進行檢驗

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn = 1003; 
int que[maxn*maxn][2],cnt=0;
int map[maxn][maxn];
int dis[maxn][maxn];
struct Node{
    int x,y;
}node[400];
int fs[5]={1,0,-1,0,1};
int n,m;
void bfs() {
    int head=0,tail=cnt;
    while(head<=tail) {
        int x=que[++head][0],y=que[head][1];
        for(int i=0;i<4;i++) {
            int xx=x+fs[i],xy=y+fs[i+1];
            if(xx>=1&&xx<=n&&xy>=1&&xy<=m&&!map[xx][xy]&&!dis[xx][xy]) {
                dis[xx][xy]=dis[x][y]+1;
                que[++tail][0]=xx,que[tail][1]=xy;
            }
        }
    }
}
bool vis[maxn][maxn];
bool judge(int ans) {
    int head=0,tail=1;
    memset(que,0,sizeof que);
    memset(vis,0,sizeof vis);
    que[1][0]=1,que[1][1]=1,vis[1][1]=1;
    while(head<tail) {
        int x=que[++head][0],y=que[head][1];
        for(int i=0;i<4;i++) {
            int xx=x+fs[i],xy=y+fs[i+1];
            if(xx>=1&&xx<=n&&xy>=1&&xy<=m&&dis[xx][xy]>=ans&&!map[xx][xy]&&!vis[xx][xy]) {
                if(xx==n&&xy==m)return true;
                que[++tail][0]=xx,que[tail][1]=xy;vis[xx][xy]=1;
            }
        }
    }
    return false;
}
int main() {
    freopen("run.in","r",stdin);
    freopen("run.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&map[i][j]);
            if(map[i][j]==1)que[++cnt][0]=i,que[cnt][1]=j;
            }
    if(map[1][1]||map[n][m]){
        puts("0");return 0;
    }
    bfs();
    int l=0,r=1000006;
    int ans;
    while(l<=r) {
        int mid=(l+r)/2;
        if(judge(mid)) {
            l=mid+1;
            ans=mid;
        }
        else r=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

T3 : 20

錯因 不會....tarjan+亂搞

仙人掌(cactus)
Time Limit:1000ms Memory Limit:64MB
題目描述
LYK 在沖刺清華集訓(THUSC) !於是它開始研究仙人掌?,它想來和你一起分享它最近
研究的結果。
如果在一個無向連通圖中任意一條邊至多屬於一個簡單環 (簡單環的定義為每個點至多
經過一次) ,且不存在自環,我們稱這個圖為仙人掌。
LYK 覺得仙人掌還是太簡單了,於是它定義了屬於自己的仙人掌。
定義一張圖為美妙的仙人掌, 當且僅當這張圖是一個仙人掌且對於任意兩個不同的點 i,j,
存在一條從 i 出發到 j 的路徑,且經過的點的個數為|j-i|+1 個。
給定一張 n 個點 m 條邊且沒有自環的圖,LYK 想知道美妙的仙人掌最多有多少條邊。
數據保證整張圖至少存在一個美妙的仙人掌。
輸入格式(cactus.in)
第一行兩個數 n,m 表示這張圖的點數和邊數。
接下來 m 行,每行兩個數 u,v 表示存在一條連接 u,v 的無向邊。
輸出格式(cactus.out)
一個數表示答案
輸入樣例
4 6
1 2
1 3
1 4
2 3
2 4
3 4
輸出樣例
4
樣例解釋
選擇邊 1-2,1-3,2-3,3-4,能組成美妙的仙人掌,且不存在其它美妙仙人掌有超過 4 條
邊。
數據範圍
對於 20%的數據 n<=3。
對於 40%的數據 n<=5。
對於 60%的數據 n<=8。
對於 80%的數據 n<=1000。
對於 100%的數據 n<=100000 且 m<=min(200000,n*(n-1)/2)。

對於i和i+1點要過2個點,即只能為這兩個點之間直接有一條邊,那麽這n-1條連接i和i+1的邊一定選,選完這些邊之後正好滿足

要在保證仙人掌的前提下多選邊

保證邊沒有交集因為現在已經選了i到i+1的邊其他的邊會和現在已經選的邊形成環,否則,兩個邊有交集,不滿足仙人掌的性質,所以問題轉化成了線段覆蓋

#include<cstdio>
#include<algorithm> 
using namespace std;
const int maxn =200010;
int n,m,cnt,ans;
struct Edge{
    int x,y; 
    bool operator < (const Edge &x)const{
        return y<x.y;
    }
}edge[maxn*2];
int main()
{
    freopen("cactus.in","r",stdin);
    freopen("cactus.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int a,b,i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        if(a>b)swap(a,b);
        if(a!=b-1)edge[++cnt].x=a,edge[cnt].y=b;
    }
    sort(edge+1,edge+cnt+1);
    int tail=-1;
    for(int i=1;i<=cnt;i++) {
        if(edge[i].x>=tail) {
            tail=edge[i].y;
            ans++;
        }
    }
    printf("%d\n",ans+n-1);
    return 0;
}

2017 09 17 測驗解題報告