CTU Open 2013

/*
Fractional Lotion

題意:給出 n ,求有多少對 (x, y),滿足 1/x + 1/y = 1/n。

分析:式子變換一下,y = nx / (x-n),由於 n <= 10000, y > 0, 而且由於 x 和 y 沒有順

序限制,即 (x, y) 和 (y, x) 爲同一種情況,所以 x 的枚舉範圍爲 n < x <= 2n
*/
代碼:
#include<bits/stdc++.h>
using namespace std;

int main() {
    int o, n, x, ans;
    while(scanf("%d/%d", &o, &n) != EOF) {
        x = n << 1;
        ans = 0;
        while(x > n) {
            if(n * x % (x - n) == 0) {
                ans++;
            }
            x--;
        }
        printf("%d\n", ans);
    }
    return 0;
}

/*
Folded Map

題意:給出一個 Ar X Ac 的圖,要求用最少的 Tr X Tc 的矩形 R 覆蓋所有的 'X',問最少要多少個這樣的矩形。

分析:有一個簡單又巧妙地做法。

首先把邊界 Ar、Ac 擴大至 Ar+Tr、Ac+Tc,然後用一個數組cnt_tile[i][j]表示右下角爲(i, j)的矩形R所覆蓋的 'X' 的數量,那麼我們可以

枚舉{ (x, y) | (0 <= x < Tr && 0 <= y < Tc) }中的點作爲鋪矩形的起點,然後模擬鋪矩形的行爲,鋪滿整個圖,統計 (cnt_tile[x][y] > 

0) 的數目,即有覆蓋到'X'的矩形,即是所需矩形的數目,所有的起點都試一遍取最優值即可。具體參見代碼,很好理解。
PS: cnt_tile[][]數組的實現方法有很多,可以用代碼裏的方法掃描全圖得到,也可以用前綴和等方法。
*/
代碼:
#include<bits/stdc++.h>
using namespace std;
const int N = 1111;
bool data[N][N];
int cnt_left[N][N], cnt_tile[N][N];
int ar, ac, tr, tc;

int cal(int x, int y) {
    int ret = 0;
    for(int i = x; i < ar + tr; i += tr) {
        for(int j = y; j < ac + tc; j += tc) {
            if(cnt_tile[i][j]) { ret++; }
        }
    }
    return ret;
}

int main() {
    char ch;
    int ans, cnt;
    //freopen("in.txt", "r", stdin);
    while(scanf("%d%d%d%d", &ar, &ac, &tr, &tc) != EOF) {
        for(int i = 0; i < ar; i++) {
            getchar();
            for(int j = 0; j < ac; j++) {
                ch = getchar();
                data[i][j] = (ch == 'X');
            }
        }

        for(int i = 0; i < ar + tr; i++) {
            cnt = 0;
            for(int j = 0; j < ac + tc; j++) {
                if(i < ar && j < ac && data[i][j]) cnt++;
                if(j - tc >= 0 && i < ar && data[i][j - tc]) {
                    cnt--;
                }
                cnt_left[i][j] = cnt;
            }
        }

        for(int j = 0; j < ac + tc; j++) {
            cnt = 0;
            for(int i = 0; i < ar + tr; i++) {
                cnt += cnt_left[i][j];
                if(i - tr >= 0 && cnt_left[i - tr][j]) {
                    cnt -= cnt_left[i - tr][j];
                }
                cnt_tile[i][j] = cnt;
            }
        }

        ans = N * N;
        for(int i = 0; i < tr; i++) {
            for(int j = 0; j < tc; j++) {
                ans = min(ans, cal(i, j));
            }
        }

        printf("%d\n", ans);
    }
    return 0;
}

/*
Furry Nuisance

題意:給出一個n個點m條邊的圖,問能不能通過移除一些點和一些邊得到一個只有4個度爲1的節點的連通圖。

分析:如果比較熟悉bfs,應該很容易想到。bfs是從起點開始然後逐層拓展的,那麼可以從圖的任意一點進行bfs,若當拓展層的節點數 + 不能

再拓展的點的數量 >= 4,那必定可以通過刪除一些點和邊得到一個只有4個度爲1的節點的連通圖。需要注意的是如果從度爲1的點開始bfs的話

,那麼該點必定可以加到所求的連通圖上,這時候只要拓展層的節點數 + 不能再拓展的點的數量 >= 3即可。
*/
代碼:
#include<bits/stdc++.h>
using namespace std;
const int N = 10001;
const int M = 40004;
int n, m, d[N];
bool vis[N];
vector<int>edge[M];

bool bfs(int s, int min_cnt) {
    vis[s] = true;
    queue<int>q[2];
    q[0].push(s);
    int x, y, si, lef = 0;
    while(!q[0].empty()) {
        swap(q[0], q[1]);
        while(!q[1].empty()) {
            x = q[1].front();
            q[1].pop();
            si = edge[x].size();
            bool inq = false;
            for(int i = 0; i < si; i++) {
                y = edge[x][i];
                if(!vis[y]) {
                    inq = true;
                    vis[y] = true;
                    q[0].push(y);
                }
            }
            if(!inq) lef++;
        }
        //cout << q[0].size() + lef << ' ' << min_cnt << endl;
        if(q[0].size() + lef >= min_cnt) {
            return true;
        }
    }
    return false;
}

int main() {
    int x, y;
    while(scanf("%d%d", &n, &m) != EOF) {
        for(int i = 1; i <= n; i++) {
            edge[i].clear();
            vis[i] = false;
            d[i] = 0;
        }
        for(int i = 0; i < m; i++) {
            scanf("%d%d", &x, &y);
            edge[x].push_back(y);
            edge[y].push_back(x);
            d[x]++;
            d[y]++;
        }
        bool flag = false;
        for(int i = 1; i <= n; i++) {
            if(!vis[i]) {
                if(bfs(i, 4 - (d[i] == 1))) {
                    flag = true;
                    break;
                }
            }
        }
        if(flag) { puts("YES"); }
        else { puts("NO"); }
    }
    return 0;
}

/*
Fence Orthogonality

題意:給出n個點,用一個周長最小的矩形覆蓋所有點,輸出矩形的周長。

分析:幾何題,凸包 + 旋轉卡殼。

如果不知道這兩個東西的話,可以看下這下面這裏
Graham掃描求凸包算法:
http://blog.csdn.net/tmljs1988/article/details/7259331

如果還不懂,這些講解視頻也是不錯的:
http://v.baidu.com/v?word=graham+%E5%87%B8%E5%8C%85&ct=301989888&rn=20&pn=0&db=0&s=0&fbl=800&ie=utf-8

旋轉卡殼詳解:http://blog.csdn.net/hanchengxi/article/details/8639476

參考代碼:
http://blog.csdn.net/wsx1754175/article/details/19355205
*/

/*
Flower Pots

題意:給出12種不同的5連塊,分別由12個字母表示,給出4個5連塊,前兩個爲一組,後兩個爲一組,問能不能拼出兩個一樣的圖案。注意不能

跨組!只能同組內拼,可以旋轉也可以翻轉。

分析:感覺是很麻煩的模擬和搜索。。。待解決
*/

/*
Frustrated Queue

題意:給出一個由點和括號組成的偶數長度的字符串,每一個字符代表一個人,他們在排隊上廁所。已知上廁所的費用爲0.5元,等待的人中有

一半帶有0.5元的硬幣,另一半有1元的硬幣。左括號表示當前位置的人只有0.5元的硬幣,右括號表示當前位置的人只有1元的硬幣,點則表示爲

兩種情況之一,剛開始廁所管理員是沒有任何硬幣的,問有多少種不會出現堵塞的序列,輸出方案數後6位。

)....... 是必定會堵塞的,因爲第一位只有1元的硬幣,管理員沒辦法給他找錢。

分析:DP,dp[i][j]表示前i個人中,其中有j個人帶有0.5元硬幣的合法方案數。
設 dp[0][0] = 1;
那麼當 s[i] == '('時,dp[i][j] = dp[i-1][j-1];
    當 s[i] == ')'時,dp[i][j] = dp[i-1][j];
    當 s[i] == '.'時,dp[i][j] = dp[i-1][j-1] + dp[i-1][j];

第二層循環j可以從(i+1)/2開始枚舉,因爲前i和人中至少有一半人有0.5元的硬幣纔可能存在合法情況。
*/
代碼:
#include<bits/stdc++.h>
using namespace std;

const int m = 1e6;
char s[2000];
int dp[1001][501];

int main() {
    while(scanf("%s", s + 1) != EOF) {
        int n = strlen(s + 1);
        dp[0][0] = 1;
        for(int i = 1; i <= n; i++) {
                for(int j = (i + 1) / 2; j <= i && j <= n / 2; j++) {
                    if(s[i] == '.') {
                        dp[i][j] = (dp[i-1][j] + dp[i-1][j-1]) % m;
                    }
                    else if(s[i] == '(') {
                        dp[i][j] = dp[i-1][j-1] % m;
                    }
                    else
                        dp[i][j] = dp[i-1][j] % m;
                }
        }
        printf("%d\n", dp[n][n/2]);
    }
    return 0;
}

/*
Frozen Rose-Heads

題意:給出一個n個節點的樹和一個起點c,樹上的每條邊都帶有一個權值表示刪除這條邊的花費,要求用最少花費刪除一些邊使得節點c和所有

的葉子節點都不連通,輸出最小花費。

分析:一眼看過去,就是一道裸的最大流。只要構建一個匯點t連向所有葉子節點,然後求這個圖c到t的最大流即可。但是由於這是一顆樹,沒

有那麼複雜,所以也可以用dfs做,可以從c點出發對樹進行後序遍歷,之後不斷把最優值返回到父親節點就行了,具體參見代碼。
*/
代碼:
#include<bits/stdc++.h>
using namespace std;

#define v first
#define w second
const int inf = 0x3f3f3f3f;
typedef pair<int,int> pii;
vector<pii>edge[1001];
bool vis[1001];

int dfs(int u, int par) {
    vis[u] = true;
    int son = 0;
    vector<pii>::iterator p;
    for(p = edge[u].begin(); p != edge[u].end(); ++p) {
        if(!vis[p->v]) {
            son += dfs(p->v, p->w);
        }
    }
    if(!son) return par;
    return min(par, son);
}

int main() {
    int n, s, u, v, w;
    while(scanf("%d%d", &n, &s) != EOF) {
        for(int i = 1; i <= n; i++) {
            edge[i].clear();
            vis[i] = false;
        }
        for(int i = 1; i < n; i++) {
            scanf("%d%d%d", &u, &v, &w);
            edge[u].push_back(pii(v, w));
            edge[v].push_back(pii(u, w));
        }
        printf("%d\n", dfs(s, inf));
    }
    return 0;
}

/*
False Sense of Security

題意:就是根據給出的編碼表把給出的字符串翻譯,然後得到一個點和下劃線組成的字符序列和一個長度序列,把長度序列翻轉,再按照這個長

度序列把字符序列翻譯成另一個字符串,輸出這個字符串。

分析:打表模擬。
*/
代碼:
略
發佈了31 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章