1. 程式人生 > >NIOP 09 題解

NIOP 09 題解

簡單 很好 不能 view empty 價格 練習 hide min

2009 NOIP 提高組 題解

這次考試,呃,除了第一題就沒怎麽拿分。後面幾道題都比較難想,想到了又不怎麽寫的出來,哎。

幾道題總的難度都不是很大,總結最近幾次做題來說,在圖論上只是還是很欠缺,做題都不怎麽會去想圖論方面的知識,但其實只要能想到用圖論知識的話最近的幾道題都還是很好處理的。假期要在復習一遍圖論了。

這次的題主要是讀懂題。

T1 潛伏者 T2 Hankson的趣味題 T3 最優貿易 T4 靶形數獨

T1

額,該怎麽判斷怎麽判斷吧。旁邊的cyy同學認為推出25個字母的密碼可以自行推出最後一個,怎麽說呢,他高估了競賽題裏面間諜的智商。加之題目中有說可能有重復的字母出現,哇,間諜你推過了字母你還能再用一次,哎,智商可想而知了,難保推完25個字母在推一次用過的字母。

T2

想了很久,想的是分解質因數,然後依次相乘進行判斷。嘛,思路是正確的。但這樣做考慮的情況蠻多的,我是自最小依次向上乘上去的,還有就是多出來的數乘每個因子沒有乘。這種還是應該多測試來以防萬一。

T3

比較難想,本來是說廣搜前50%的點的,但廣搜不知怎麽就爆掉了,還有之前寫的時候搞混了.pop 和 .front 這點需要註意。比較容易理解的方法的話就是Spfa求最大最小值(註意利用將圖反向來求取)。

/*首先看題目以後我們知道這個題目一定是貪心,貪心的思路也很簡單就是在最便宜的地方買商品在最貴的地方賣出去賺取差價,但是如果我們直接比較出最大值最小值做差是有問題的,當然不可能這個簡單這個題目是當年的壓軸題啊。這麽簡單怎麽玩。【雖然實際上也不難】因為那個人在不斷的往前面走並在前面買東西在後面賣,所以我就把原來的邊拆了建在兩個圖上。把所有的邊正向建一張圖,然後把邊反過來再建一次,這樣我原來的圖就有兩個了,於是我在正向的圖上跑一邊SPFA**不斷更新從1到該點的最小值然後我再在

反向的圖上面跑第二遍SPFA然後更新最大值**並且把每個點的最大值與最小值做差來更新答案。這樣就是正確的姿勢啦。
【證明】因為我們正向的跑了一邊spfa更新最小值就相當於把起點到每個點的最小值求出來了,然後我第二遍spfa就做了兩件事情第一個證明了連通性【因為我這個題目中有一些路是單向的,所以說可能某些點買的價格特別低或者特別高,但是我去的那兒是陷阱,你進去了就出不來了這樣你的答案就是錯的了,所以我把圖反過來建這樣你從終點可以反著跑到這個點也就代表這個點可以正著跑到終點,這就相當於證明了連通性】
第二個事情就是不斷的貨比三家,計算利潤和差值。 */

T4

是準備搞出數獨再進行處理的,但驚訝的發現我填不來數獨啊天。用excel填了半天果斷還是放了。

看到做法有DFS的,還有用啟發式搜索的,不過較為感興趣的還是 跳舞鏈 求解數獨,感覺好神奇的高級算法,看了半天沒有看的懂,不過hzwer大神是用的DFS,說是時間很尷尬。

這次的題目總的來說並沒什麽特別上難度的題,但是這一年的題目還是很有借鑒意義的,因為題目普遍難懂(可能只是我的語文水平不咋滴),但還是反應出對知識理解的不透徹,不能很好的熟練應用。總的來說,還是要加強對題目的練習與理解,這也是不管學習什麽都必須的。

技術分享
 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 string s1,s2,s3;
 5 char standard[110],ops[110];
 6 bool comp[50];
 7 int main()
 8 {
 9     freopen("spy.in","r",stdin);
10     freopen("spy.out","w",stdout);
11     cin >> s1 >> s2 >> s3;
12     for(int i=0;i<s1.size();i++){
13         if((comp[s2[i] - A] && ops[s2[i] - A] != s1[i]) || (standard[s1[i] - A] && standard[s1[i] - A] != s2[i])){
14             cout << "Failed"; return 0;
15         }
16         ops[s2[i] - A] = s1[i];
17         comp[s2[i] - A] = true;
18         standard[s1[i] - A] = s2[i];
19     }
20     for(int i=0;i<26;i++) if(!comp[i]) {cout << "Failed"; return 0;}
21     for(int i=0;i<s3.size();i++){
22         cout << standard[s3[i] - A];
23     }
24     return 0;
25 }
View Code 技術分享
第二題被我吃了,不要問我為什麽,我才不會告訴你們我穿了兩個一模一樣的錯誤代碼回家,哼。
View Code 技術分享
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define MAXN 500000
int n,m,e = 1,ans,head[MAXN][2],MAX[MAXN],MIN[MAXN],Data[MAXN];
bool inq[MAXN];
queue<int>q;
struct node{
    int v,next;
} edge[MAXN];
void addedge(int u,int v)
{
    edge[e].next = head[u][0];
    edge[e].v = v;
    head[u][0] = e++;
    edge[e].next = head[v][1];
    edge[e].v = u;
    head[v][1] = e++;
}
void spfa_1()
{
    q.push(1);
    inq[1] = true;
    MIN[1] = Data[1];
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        inq[x] = false;
        for(int i = head[x][0]; i; i = edge[i].next)
        {
            int v = edge[i].v;
            if(MIN[v] > MIN[x] || MIN[v] > Data[v])
            {
                MIN[v] = min(MIN[x],Data[v]);
                if(!inq[v]) q.push(v),inq[v] = true;
            }
        }
    }
}
void spfa_2()
{
    q.push(n);
    inq[n] = true;
    MAX[n] = Data[n];
    ans = max(ans,MAX[n] - MIN[n]);
    while(!q.empty())
    {
        int x = q.front();
        q.pop();
        inq[x] = false;
        for(int i = head[x][1]; i; i = edge[i].next)
        {
            int v = edge[i].v;
            if(MAX[v] < MAX[x] || MAX[v] < Data[v])
            {
                MAX[v] = max(MAX[x],Data[v]);
                ans = max(MAX[v] - MIN[v],ans);
                if(!inq[v]) q.push(v),inq[v] = true;
            }
        }
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++)
        scanf("%d",&Data[i]), MIN[i] = 105;
    int u,v,k;
    for(int i = 1; i <= m; i++)
    {
        scanf("%d%d%d",&u,&v,&k);
        addedge(u,v);
        if(k == 2) addedge(v,u);
    }
    spfa_1();
    memset(inq,0,sizeof(inq));
    spfa_2();
    printf("%d\n",ans);
    return 0;
}
View Code 技術分享
#include<iostream>
#include<cstdio>
#define searchnext(x,y) y==9? search(x+1,1):search(x,y+1)
using namespace std;
bool r[10][10],l[10][10],s[10][10];//行,列,小九宮格
int a[10][10],b[10][10];
int ans=-1,score;
int getscore(int x,int y,int k)
{
    if(x==5&&y==5)return 10*k;
    else if(x>=4&&x<=6&&y>=4&&y<=6)return 9*k;
    else if(x>=3&&x<=7&&y>=3&&y<=7)return 8*k;
    else if(x>=2&&x<=8&&y>=2&&y<=8)return 7*k;
    else return 6*k;
}
bool fillin(int x,int y,int k)
{
    if(r[x][k])return 0;
    if(l[y][k])return 0;
    if(s[(x-1)/3*3+(y-1)/3+1][k])return 0;
    b[x][y]=k;
    r[x][k]=l[y][k]=s[(x-1)/3*3+(y-1)/3+1][k]=1;
    score+=getscore(x,y,k);
    return 1;
}
void del(int x,int y,int k)
{
    b[x][y]=0;
    r[x][k]=l[y][k]=s[(x-1)/3*3+(y-1)/3+1][k]=0;
}
void search(int x,int y)
{
    if(x==10&y==1)
    {
        ans=max(ans,score);
        return;
    }
    if(b[x][y])searchnext(x,y);
    else
        for(int i=1; i<=9; i++)
        {
            int t=score;
            if(fillin(x,y,i))
            {
                searchnext(x,y);
                del(x,y,i);
                score=t;
            }
        }
}
int main()
{
    for(int i=9; i>0; i--)
        for(int j=9; j>0; j--)
        {
            scanf("%d",&a[i][j]);
            if(a[i][j])fillin(i,j,a[i][j]);
        }
    search(1,1);
    printf("%d",ans);
    return 0;
}
View Code

NIOP 09 題解