2018年1月26日天梯賽練習1


7-1 尋找250(10 分)

對方不想和你說話,並向你扔了一串數…… 而你必須從這一串數字中找到“250”這個高大上的感人數字。

輸入格式:

輸入在一行中給出不知道多少個絕對值不超過1000的整數,其中保證至少存在一個“250”。

輸出格式:

在一行中輸出第一次出現的“250”是對方扔過來的第幾個數字(計數從1開始)。題目保證輸出的數字在整型范圍內。

輸入樣例:

888 666 123 -233 250 13 250 -222

輸出樣例:

5
作者: 陳越
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int main()
{
    int n,f=0,i=1;
    while(~scanf("%d",&n))
    {
        if(n==250&&!f)f=i;
        i++;
    }
    printf("%d",f);
    return 0;
}

7-2 日期格式化(5 分)

世界上不同國家有不同的寫日期的習慣。比如美國人習慣寫成“月-日-年”,而中國人習慣寫成“年-月-日”。下面請你寫個程序,自動把讀入的美國格式的日期改寫成中國習慣的日期。

輸入格式:

輸入在一行中按照“mm-dd-yyyy”的格式給出月、日、年。題目保證給出的日期是1900年元旦至今合法的日期。

輸出格式:

在一行中按照“yyyy-mm-dd”的格式給出年、月、日。

輸入樣例:

03-15-2017

輸出樣例:

2017-03-15
作者: 陳越
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int main()
{
   int y,m,d;
   scanf("%d-%d-%d",&m,&d,&y);
   printf("%d-%02d-%02d",y,m,d);
    return 0;
}

7-3 閱覽室(20 分)

天梯圖書閱覽室請你編寫一個簡單的圖書借閱統計程序。當讀者借書時,管理員輸入書號並按下S鍵,程序開始計時;當讀者還書時,管理員輸入書號並按下E鍵,程序結束計時。書號為不超過1000的正整數。當管理員將0作為書號輸入時,表示一天工作結束,你的程序應輸出當天的讀者借書次數和平均閱讀時間。

注意:由於線路偶爾會有故障,可能出現不完整的紀錄,即只有S沒有E,或者只有E沒有S的紀錄,系統應能自動忽略這種無效紀錄。另外,題目保證書號是書的唯一標識,同一本書在任何時間區間內只可能被一位讀者借閱。

輸入格式:

輸入在第一行給出一個正整數N(10),隨后給出N天的紀錄。每天的紀錄由若干次借閱操作組成,每次操作占一行,格式為:

書號([1, 1000]內的整數) 鍵值SE) 發生時間hh:mm,其中hh是[0,23]內的整數,mm是[0, 59]內整數)

每一天的紀錄保證按時間遞增的順序給出。

輸出格式:

對每天的紀錄,在一行中輸出當天的讀者借書次數和平均閱讀時間(以分鍾為單位的精確到個位的整數時間)。

輸入樣例:

3
1 S 08:10
2 S 08:35
1 E 10:00
2 E 13:16
0 S 17:00
0 S 17:00
3 E 08:10
1 S 08:20
2 S 09:00
1 E 09:20
0 E 17:00

輸出樣例:

2 196
0 0
1 60
作者: 陳越
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        double t=0;
        int s=0,x,p,q;
        map<int,char>a;
        map<int,int>b;
        char m;
        while(scanf("%d %c%d:%d",&x,&m,&p,&q),x)
        {
            if(m=='S')
                a[x]='S',b[x]=p*60+q;
            else if(a[x]=='S')
                t+=p*60+q-b[x],s++,a[x]='0';
        }
        if(s)t/=s;
        printf("%d %d\n",s,(int)(t+0.5));
    }
    return 0;
}

7-4 穩贏(15 分)

大家應該都會玩“錘子剪刀布”的游戲:兩人同時給出手勢,勝負規則如圖所示:

現要求你編寫一個穩贏不輸的程序,根據對方的出招,給出對應的贏招。但是!為了不讓對方輸得太慘,你需要每隔K次就讓一個平局。

輸入格式:

輸入首先在第一行給出正整數K(10),即平局間隔的次數。隨后每行給出對方的一次出招:ChuiZi代表“錘子”、JianDao代表“剪刀”、Bu代表“布”。End代表輸入結束,這一行不要作為出招處理。

輸出格式:

對每一個輸入的出招,按要求輸出穩贏或平局的招式。每招占一行。

輸入樣例:

2
ChuiZi
JianDao
Bu
JianDao
Bu
ChuiZi
ChuiZi
End

輸出樣例:

Bu
ChuiZi
Bu
ChuiZi
JianDao
ChuiZi
Bu
作者: 陳越
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

小模擬
#include<bits/stdc++.h>
using namespace std;
map<string,string>M;
int main()
{
    M["ChuiZi"]="Bu",M["Bu"]="JianDao",M["JianDao"]="ChuiZi";
    int n,num=0;
    cin>>n;
    string s;
    while(cin>>s,s!="End")
    {
        num++;
        if(num<=n)
        {
            cout<<M[s]<<"\n";
        }
        else
        {
            num=0,cout<<s<<"\n";
        }
    }
    return 0;
}

7-5 宇宙無敵大招呼(5 分)

據說所有程序員學習的第一個程序都是在屏幕上輸出一句“Hello World”,跟這個世界打個招呼。作為天梯賽中的程序員,你寫的程序得高級一點,要能跟任意指定的星球打招呼。

輸入格式:

輸入在第一行給出一個星球的名字S,是一個由不超過7個英文字母組成的單詞,以回車結束。

輸出格式:

在一行中輸出Hello S,跟輸入的S星球打個招呼。

輸入樣例:

Mars

輸出樣例:

Hello Mars
作者: 陳越
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

Hello World題
#include<bits/stdc++.h>
using namespace std;
map<string,string>M;
int main()
{
    string s;
    cin>>s;
    cout<<"Hello "<<s<<"\n";
    return 0;
}

7-6 整除光棍(20 分)

這里所謂的“光棍”,並不是指單身汪啦~ 說的是全部由1組成的數字,比如1、11、111、1111等。傳說任何一個光棍都能被一個不以5結尾的奇數整除。比如,111111就可以被13整除。 現在,你的程序要讀入一個整數x,這個整數一定是奇數並且不以5結尾。然后,經過計算,輸出兩個數字:第一個數字s,表示x乘以s是一個光棍,第二個數字n是這個光棍的位數。這樣的解當然不是唯一的,題目要求你輸出最小的解。

提示:一個顯然的辦法是逐漸增加光棍的位數,直到可以整除x為止。但難點在於,s可能是個非常大的數 —— 比如,程序輸入31,那么就輸出3584229390681和15,因為31乘以3584229390681的結果是111111111111111,一共15個1。

輸入格式:

輸入在一行中給出一個不以5結尾的正奇數x<1000)。

輸出格式:

在一行中輸出相應的最小的sn,其間以1個空格分隔。

輸入樣例:

31

輸出樣例:

3584229390681 15
作者: 翁愷
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

大數模擬
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    int num=0,n;
    int t=1;
    scanf("%d",&n);
    for(;;)
    {
        num++;
        if(s.length()||t/n)s+='0'+t/n;
        t%=n;
        if(!t)
        {
            cout<<s<<" "<<num<<"\n";
            return 0;
        }
        t=t*10+1;
    }
}

7-7 裝睡(10 分)

你永遠叫不醒一個裝睡的人 —— 但是通過分析一個人的呼吸頻率和脈搏,你可以發現誰在裝睡!醫生告訴我們,正常人睡眠時的呼吸頻率是每分鍾15-20次,脈搏是每分鍾50-70次。下面給定一系列人的呼吸頻率與脈搏,請你找出他們中間有可能在裝睡的人,即至少一項指標不在正常范圍內的人。

輸入格式:

輸入在第一行給出一個正整數N(10)。隨后N行,每行給出一個人的名字(僅由英文字母組成的、長度不超過3個字符的串)、其呼吸頻率和脈搏(均為不超過100的正整數)。

輸出格式:

按照輸入順序檢查每個人,如果其至少一項指標不在正常范圍內,則輸出其名字,每個名字占一行。

輸入樣例:

4
Amy 15 70
Tom 14 60
Joe 18 50
Zoe 21 71

輸出樣例:

Tom
Zoe
作者: 陳越
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        string s;
        int a,b;
        cin>>s>>a>>b;
        if(a<15||a>20||b<50||b>70)
            cout<<s<<"\n";
    }
    return 0;
}

7-8 矩陣A乘以B(15 分)

給定兩個矩陣A和B,要求你計算它們的乘積矩陣AB。需要注意的是,只有規模匹配的矩陣才可以相乘。即若A有Ra​​行、Ca​​列,B有Rb​​行、Cb​​列,則只有Ca​​與Rb​​相等時,兩個矩陣才能相乘。

輸入格式:

輸入先后給出兩個矩陣A和B。對於每個矩陣,首先在一行中給出其行數R和列數C,隨后R行,每行給出C個整數,以1個空格分隔,且行首尾沒有多余的空格。輸入保證兩個矩陣的R和C都是正數,並且所有整數的絕對值不超過100。

輸出格式:

若輸入的兩個矩陣的規模是匹配的,則按照輸入的格式輸出乘積矩陣AB,否則輸出Error: Ca != Rb,其中CaA的列數,RbB的行數。

輸入樣例1:

2 3
1 2 3
4 5 6
3 4
7 8 9 0
-1 -2 -3 -4
5 6 7 8

輸出樣例1:

2 4
20 22 24 16
53 58 63 28

輸入樣例2:

3 2
38 26
43 -5
0 17
3 2
-11 57
99 68
81 72

輸出樣例2:

Error: 2 != 3
作者: 陳越
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

線代概念題
#include<bits/stdc++.h>
using namespace std;
int A[105][105],B[105][105],C[105][105];
int main()
{
    int a,b;
    cin>>a>>b;
    for(int i=0; i<a; i++)
        for(int j=0; j<b; j++)
            cin>>A[i][j];
    int c,d;
    cin>>c>>d;
    for(int i=0; i<c; i++)
        for(int j=0; j<d; j++)
            cin>>B[i][j];
    if(b!=c)
        cout<<"Error: "<<b<<" != "<<c;
    else
    {
        cout<<a<<" "<<d<<"\n";
        for(int i=0; i<a; i++)
            for(int j=0; j<d; j++)
                for(int k=0; k<b; k++)
                    C[i][j]+=A[i][k]*B[k][j];
        for(int i=0; i<a; i++)
        {
            cout<<C[i][0];
            for(int j=1; j<d; j++)
                cout<<" "<<C[i][j];
            cout<<"\n";
        }
    }
}

7-9 點贊狂魔(25 分)

微博上有個“點贊”功能,你可以為你喜歡的博文點個贊表示支持。每篇博文都有一些刻畫其特性的標簽,而你點贊的博文的類型,也間接刻畫了你的特性。然而有這么一種人,他們會通過給自己看到的一切內容點贊來狂刷存在感,這種人就被稱為“點贊狂魔”。他們點贊的標簽非常分散,無法體現出明顯的特性。本題就要求你寫個程序,通過統計每個人點贊的不同標簽的數量,找出前3名點贊狂魔。

輸入格式:

輸入在第一行給出一個正整數N(100),是待統計的用戶數。隨后N行,每行列出一位用戶的點贊標簽。格式為“Name F1​​FK​​”,其中Name是不超過8個英文小寫字母的非空用戶名,1K1000,Fi​​(i=1,,K)是特性標簽的編號,我們將所有特性標簽從1到107編號。數字間以空格分隔。

輸出格式:

統計每個人點贊的不同標簽的數量,找出數量最大的前3名,在一行中順序輸出他們的用戶名,其間以1個空格分隔,且行末不得有多余空格。如果有並列,則輸出標簽出現次數平均值最小的那個,題目保證這樣的用戶沒有並列。若不足3人,則用-補齊缺失,例如mike jenny -就表示只有2人。

輸入樣例:

5
bob 11 101 102 103 104 105 106 107 108 108 107 107
peter 8 1 2 3 4 3 2 5 1
chris 12 1 2 3 4 5 6 7 8 9 1 2 3
john 10 8 7 6 5 4 3 2 1 7 5
jack 9 6 7 8 9 10 11 12 13 14

輸出樣例:

jack chris john
作者: 陳越
單位: 浙江大學
時間限制: 200ms
內存限制: 64MB
代碼長度限制: 16KB

#include<bits/stdc++.h>
using namespace std;
struct T
{
    string s;
    int sum,num;
} t ;
int cmp(T a,T b)
{
    return a.sum>b.sum||a.sum==b.sum&&a.num<b.num;
}
int main()
{
    int n;
    cin>>n;
    vector<T>V;
    for(int i=0; i<n; i++)
    {
        set<int>s;
        cin>>t.s;
        cin>>t.num;
        t.sum=0;
        for(int j=0,x; j<t.num; j++)
        {
            cin>>x;
            if(!s.count(x))
                s.insert(x),t.sum++;
        }
        V.push_back(t);
    }
    sort(V.begin(),V.end(),cmp);
    t.s="-";
    while(V.size()<3)V.push_back(t);
    cout<<V[0].s;
    for(int i=1; i<3; i++)
        cout<<" "<<V[i].s;
    return 0;
}

7-10 重排鏈表(25 分)

給定一個單鏈表 L1​​→L2​​→⋯→Ln1​​→Ln​​,請編寫程序將鏈表重新排列為 Ln​​→L1​​→Ln1​​→L2​​→⋯。例如:給定L為1→2→3→4→5→6,則輸出應該為6→1→5→2→4→3。

輸入格式:

每個輸入包含1個測試用例。每個測試用例第1行給出第1個結點的地址和結點總個數,即正整數N(105​​)。結點的地址是5位非負整數,NULL地址用1表示。

接下來有N行,每行格式為:

Address Data Next

其中Address是結點地址;Data是該結點保存的數據,為不超過105​​的正整數;Next是下一結點的地址。題目保證給出的鏈表上至少有兩個結點。

輸出格式:

對每個測試用例,順序輸出重排后的結果鏈表,其上每個結點占一行,格式與輸入相同。

輸入樣例:

00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218

輸出樣例:

68237 6 00100
00100 1 99999
99999 5 12309
12309 2 00000
00000 4 33218
33218 3 -1
作者: 陳越
單位: 浙江大學
時間限制: 500ms
內存限制: 64MB
代碼長度限制: 16KB

鏈表模擬,直接找到這個序列就好,我的map沒有處理到有多余節點的,也很是奇怪
#include<bits/stdc++.h>
using namespace std;
struct T
{
    int ad,data,nxt;
} t;
map<int,T>M;
vector<T>V;
int main()
{
    int head,n;
    cin>>head>>n;
    for(int i=0; i<n; i++)
    {
        cin>>t.ad>>t.data>>t.nxt;
        M[t.ad]=t;
    }
    int f=head;
    while(f!=-1)
    {
        V.push_back(M[f]);
        head=M[f].ad;
        f=M[f].nxt;
    }
    f=head;
    for(int i=0; i<V.size(); i++)
    {
        printf("%05d ",f);
        if(i==V.size()-1)
        {
            if(i&1)
                printf("%d ",V[i/2].data);
            else printf("%d ",V[n-i/2-1].data);
            printf("-1");
        }
        else if(i&1)
            printf("%d %05d\n",V[i/2].data,V[n-i/2-2].ad),f=V[n-i/2-2].ad;
        else printf("%d %05d\n",V[n-i/2-1].data,V[i/2].ad),f=V[i/2].ad;

    }
    return 0;
}

數組的

#include <bits/stdc++.h>
using namespace std;
struct node
{
    int key,nxt,ad;
} f[1000005],f1[1000005],f2[1000005];
int main()
{
    int adr,n;
    cin>>adr>>n;
    for(int i=0,a,b,c; i<n; i++)
    {
        cin>>a>>b>>c;
        f[a].key=b;
        f[a].nxt=c;
    }
    int l=0;
    for(int i=adr; i!=-1; i=f[i].nxt)
        f1[l].ad=i,f1[l].key=f[i].key,f1[l++].nxt=f[i].nxt;
    int l1=0;
    if(l%2==0)
        for(int i=l-1,j=0; i>=(l+1)/2; i--,j++)
        {
            if(i!=j)
            {
                f2[l1].ad=f1[i].ad,f2[l1].key=f1[i].key,f2[l1++].nxt=f1[i].nxt;
                f2[l1].ad=f1[j].ad,f2[l1].key=f1[j].key,f2[l1++].nxt=f1[j].nxt;
            }
            else
            {
                f2[l1].ad=f1[i].ad,f2[l1].key=f1[i].key,f2[l1++].nxt=f1[i].nxt;
            }
        }
    else
    {
        for(int i=l-1,j=0; ; i--,j++)
        {
            if(i!=j)
            {
                f2[l1].ad=f1[i].ad,f2[l1].key=f1[i].key,f2[l1++].nxt=f1[i].nxt;
                f2[l1].ad=f1[j].ad,f2[l1].key=f1[j].key,f2[l1++].nxt=f1[j].nxt;
            }
            else
            {
                f2[l1].ad=f1[i].ad,f2[l1].key=f1[i].key,f2[l1++].nxt=f1[i].nxt;
            }
            if(i==j)break;
        }
    }
    for(int i=0; i<l1-1; i++)
        printf("%05d %d %05d\n",f2[i].ad,f2[i].key,f2[i+1].ad);
    printf("%05d %d %d\n",f2[l1-1].ad,f2[l1-1].key,-1);
}

7-11 圖着色問題(25 分)

圖着色問題是一個著名的NP完全問題。給定無向圖G=(V,E),問可否用K種顏色為V中的每一個頂點分配一種顏色,使得不會有兩個相鄰頂點具有同一種顏色?

但本題並不是要你解決這個着色問題,而是對給定的一種顏色分配,請你判斷這是否是圖着色問題的一個解。

輸入格式:

輸入在第一行給出3個整數V(0<V500)、E(0)和K(0<KV),分別是無向圖的頂點數、邊數、以及顏色數。頂點和顏色都從1到V編號。隨后E行,每行給出一條邊的兩個端點的編號。在圖的信息給出之后,給出了一個正整數N(20),是待檢查的顏色分配方案的個數。隨后N行,每行順次給出V個頂點的顏色(第i個數字表示第i個頂點的顏色),數字間以空格分隔。題目保證給定的無向圖是合法的(即不存在自回路和重邊)。

輸出格式:

對每種顏色分配方案,如果是圖着色問題的一個解則輸出Yes,否則輸出No,每句占一行。

輸入樣例:

6 8 3
2 1
1 3
4 6
2 5
2 4
5 4
5 6
3 6
4
1 2 3 3 1 2
4 5 6 6 4 5
1 2 3 4 5 6
2 3 4 2 3 4

輸出樣例:

Yes
Yes
No
No
作者: 陳越
單位: 浙江大學
時間限制: 300ms
內存限制: 64MB
代碼長度限制: 16KB

判斷是否顏色相等
#include <bits/stdc++.h>
using namespace std;
int s[505][505],F[501];
int main()
{
    int v,e,k;
    cin>>v>>e>>k;
    for(int i=0,x,y; i<e; i++)
        cin>>x>>y,s[x][y]=s[y][x]=1;
    int T;
    cin>>T;
    map<int,int> M;
    for(int i=0; i<T; i++)
    {
        M.clear();
        int f=1,c=0;
        for(int j=1; j<=v; j++)
        {
            cin>>F[j];
            if(!M[F[j]])M[F[j]]++,c++;
        }
        if(c==k)
            for(int j=1; j<v&&f; j++)
            {
                for(int l=j+1; l<=v; l++)
                    if(F[j]==F[l]&&s[j][l])
                    {
                        f=0;
                        break;
                    }
            }
        else f=0;
        if(f)cout<<"Yes\n";
        else cout<<"No\n";
    }
    return 0;
}

7-12 部落(25 分)

在一個社區里,每個人都有自己的小圈子,還可能同時屬於很多不同的朋友圈。我們認為朋友的朋友都算在一個部落里,於是要請你統計一下,在一個給定社區中,到底有多少個互不相交的部落?並且檢查任意兩個人是否屬於同一個部落。

輸入格式:

輸入在第一行給出一個正整數N(104​​),是已知小圈子的個數。隨后N行,每行按下列格式給出一個小圈子里的人:

P[1P[2⋯ P[K]

其中K是小圈子里的人數,P[i](i=1,,K)是小圈子里每個人的編號。這里所有人的編號從1開始連續編號,最大編號不會超過104​​。

之后一行給出一個非負整數Q(104​​),是查詢次數。隨后Q行,每行給出一對被查詢的人的編號。

輸出格式:

首先在一行中輸出這個社區的總人數、以及互不相交的部落的個數。隨后對每一次查詢,如果他們屬於同一個部落,則在一行中輸出Y,否則輸出N

輸入樣例:

4
3 10 1 2
2 3 4
4 1 5 7 8
3 9 6 4
2
10 5
3 7

輸出樣例:

10 2
Y
N
作者: 陳越
單位: 浙江大學
時間限制: 150ms
內存限制: 64MB
代碼長度限制: 16KB

用並查集的基本操作就行了
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int fa[N],cnt[N];
int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
int main()
{
    for(int i=0; i<N; i++)  fa[i]=i,cnt[i]=0;
    int n,q,k,a,b;
    cin>>n;
    for(int i=0; i<n; i++)
    {
        cin>>k>>a;
        cnt[a]=1;
        for(int j=1; j<k; j++)
        {
            cin>>b;
            cnt[b]=1;
            int x=find(a),y=find(b);
            if(x!=y)fa[x]=y;
        }
    }
    int s=0,num=0;
    for(int i=0; i<10004; i++)
    {
        if(cnt[i]==1)
        {
            s++;
            if(fa[i]==i)num++;
        }
    }
    printf("%d %d\n",s,num);
    cin>>q;
    while(q--)
    {
        cin>>a>>b;
        if(find(a)==find(b))
            printf("Y\n");
        else
            printf("N\n");
    }
    return 0;
}

7-15 森森美圖(30 分)

森森最近想讓自己的朋友圈熠熠生輝,所以他決定自己寫個美化照片的軟件,並起名為森森美圖。眾所周知,在合照中美化自己的面部而不美化合照者的面部是讓自己占據朋友圈高點的絕好方法,因此森森美圖里當然得有這個功能。 這個功能的第一步是將自己的面部選中。森森首先計算出了一個圖像中所有像素點與周圍點的相似程度的分數,分數越低表示某個像素點越“像”一個輪廓邊緣上的點。 森森認為,任意連續像素點的得分之和越低,表示它們組成的曲線和輪廓邊緣的重合程度越高。為了選擇出一個完整的面部,森森決定讓用戶選擇面部上的兩個像素點A和B,則連接這兩個點的直線就將圖像分為兩部分,然后在這兩部分中分別尋找一條從A到B且與輪廓重合程度最高的曲線,就可以拼出用戶的面部了。 然而森森計算出來得分矩陣后,突然發現自己不知道怎么找到這兩條曲線了,你能幫森森當上朋友圈的小王子嗎?

為了解題方便,我們做出以下補充說明:

  • 圖像的左上角是坐標原點(0,0),我們假設所有像素按矩陣格式排列,其坐標均為非負整數(即橫軸向右為正,縱軸向下為正)。
  • 忽略正好位於連接A和B的直線(注意不是線段)上的像素點,即不認為這部分像素點在任何一個划分部分上,因此曲線也不能經過這部分像素點。
  • 曲線是八連通的(即任一像素點可與其周圍的8個像素連通),但為了計算准確,某像素連接對角相鄰的斜向像素時,得分是兩個像素分數和的2​​倍。例如樣例中,經過坐標為(3,1)和(4,2)的兩個像素點的曲線,其得分應該是這兩個像素點的分數和(2+2)乘以2​​,即約為5.66。

輸入格式:

輸入在第一行給出兩個正整數N和M(5N,M100),表示像素得分矩陣的行數和列數。

接下來N行,每行M個不大於1000的非負整數,即為像素點的分值。

最后一行給出用戶選擇的起始和結束像素點的坐標(Xstart​​,Ystart​​)和(Xend​​,Yend​​)。4個整數用空格分隔。

輸出格式:

在一行中輸出划分圖片后找到的輪廓曲線的得分和,保留小數點后兩位。注意起點和終點的得分不要重復計算。

輸入樣例:

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

輸出樣例:

27.04
作者: 戴龍翱、朱建科
單位: 浙江大學
時間限制: 400ms
內存限制: 64MB
代碼長度限制: 16KB

#include<bits/stdc++.h>
using namespace std;
const int N=105;
int n,m,vis[N][N],sx,sy,ex,ey;
double s[N][N],d[N][N],mi;
const double PI=sqrt(2)-1;
int dir[8][2]= {1,0,-1,0,0,1,0,-1,1,1,-1,-1,1,-1,-1,1};
struct T
{
    int x,y;
} a,b,p;
int chaji(T a,T b,T p)
{
    return (b.x-a.x)*(p.y-a.y)-(b.y-a.y)*(p.x-a.x);
}
void spfa()
{
    memset(vis,0,sizeof vis);
    memset(d,0x7f,sizeof d);
    a.x=sx,a.y=sy,b.x=ex,b.y=ey;
    d[sx][sy]=s[sx][sy];
    queue<T>Q;
    Q.push(a);
    while(!Q.empty())
    {
        int x=Q.front().x,y=Q.front().y;
        Q.pop();
        vis[x][y]=0;
        for(int i=0; i<8; i++)
        {
            double w=0;
            p.x=x+dir[i][0],p.y=y+dir[i][1];
            if(p.x<0||p.x>=n||p.y<0||p.y>=m) continue;
            if(chaji(a,b,p)>0||p.x==ex&&p.y==ey)
            {
                w=s[p.x][p.y];
                if(i>3) w=w+(s[x][y]+s[p.x][p.y])*PI;
                if(d[p.x][p.y]>d[x][y]+w)
                {
                    d[p.x][p.y]=d[x][y]+w;
                    if(!vis[p.x][p.y])Q.push(p),vis[p.x][p.y]=1;
                }
            }
        }
    }
    mi+=d[ex][ey];
}
int main()
{
    cin>>n>>m;
    for(int i=0; i<n; i++)
        for(int j=0; j<m; j++)
            cin>>s[i][j];
    cin>>sy>>sx>>ey>>ex;
    mi=-s[ex][ey]-s[sx][sy];
    spfa();
    swap(ex,sx),swap(ey,sy);
    spfa();
    printf("%.2f",mi);
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM