/*
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
題意:就是根據給出的編碼表把給出的字符串翻譯,然後得到一個點和下劃線組成的字符序列和一個長度序列,把長度序列翻轉,再按照這個長
度序列把字符序列翻譯成另一個字符串,輸出這個字符串。
分析:打表模擬。
*/
代碼:
略
CTU Open 2013
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.