NOIPシミュレーショントレーニング2
- 260のうち。T1 100、T2 50、T3 60
- I改訂260から最初の70
- より簡単に
T1:マインスイーパ
説明
N×M(1≤N、M≤100)領域をメッシュ、バリア領域のグリッドとして「#」と表示されたグリッド数地雷原でマークされ、デジタルデータは、鉱山の領域です。左上隅から始まる、とだけ右に行くことができるか、ダウン、地雷除去車両が危険を入力することはできません、加えて、それがグリッド鉱山を旅フレイル車両が削除されます。あなたの仕事は、グリッドの左上隅(1、1)グリッドの右下隅(N、M)に到達すると地雷クリアルートのほとんどをからの逸脱を見つけ、プログラムをコンパイルすることです。以下は、4×5のサンプルグリッドで、最適なルートは6個の地雷除去地雷をクリアすることができます。
1 2 # 3 # 3 # # # # 1
入力
- 入力ファイルの最初の行は二つの数字の間の空間によって分離された2つの整数N及びMを、mine.inれます。負の数は、領域は、バリア領域であることを示す次のN個の行は、Mの整数値を有する各行は、非負数は地雷原を示し、整数は、2つの隣接する整数間の同じ行で、領域内の鉱山の総数を表し独立したスペース。
出力
- 出力ファイルmine.outのみ一列、ルートの地雷除去が存在しない場合は、右下隅、出力「無回答」、または出力クリア鉱山の最大数を表す整数の左上からの経路が存在しないこと。
サンプル入力
4 5
0 1 0 0 0
2 -1 -1 0 3
0 3 0 -1 -1
-1 -1 0 1 0
サンプル出力
6
ソリューション:
DP。しかし、それは70を取りました。コードを実装するのではなく、状況のその時のことを考えてステージに少し来るが、ちょうど付与されたためにそれを取る、これは問題になることはありませんだと思います。だから、実現可能性へのDP注意を払う後、状態を更新しました
- そう:
- その様々な条件に注意してください。境界条件を、更新条件、初期化
- 付与されたためにそれを取ってはいけません
#include <iostream>
#include <cstdio>
#define maxn 105
using namespace std;
int n, m;
int a[maxn][maxn], f[maxn][maxn];
bool can[maxn][maxn];
int main()
{
can[0][1] = can[1][0] = 1; //初始化!!
cin >> n >> m;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
cin >> a[i][j];
if(a[i][j] < 0) a[i][j] = -1;
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
if(a[i][j] != -1)
{
if(can[i - 1][j] || can[i][j - 1]) can[i][j] = 1;
if(can[i - 1][j] || can[i][j - 1]) f[i][j] = max(f[i - 1][j], f[i][j - 1]) + a[i][j];
}
if(!can[n][m]) cout << "No answer";
else cout << f[n][m];
return 0;
}
T2:シティツアー
説明
Lは、現代の都市の観光都市、クロスストリートの直線ストリップ、ルールの長方形のネットワークであり、各ストリートが整数で番号が付けられ、示されるように、ネットワークは、2つのストリートの交差点の交差点を表します:(街路番号、垂直点の番地)のレベル、都市の中心座標の規定(0、0)。(図なし、それは問題ではない)点に表現座標
市は、メンテナンスのためのM交差交通信号システムを持っており、通行不能の障害物を置かれ、都市のツアーを歩く観光客のグループが、旅をより面白くするために、彼らは次のルールを開発:市中心部からは、通りに沿ってすべてのステップを、ネットワークを介して細胞は、四方を取ることができる第一の工程に加えて、前のターンに基づいて、ステップバイステップの残りの部分は、左または右に90度、最初のステップはNだけ(0,0)、一方、出発点に戻る必要中間点が残っていますこれを繰り返すことができません。
上の図では、戻って最初に3つの手順を取ることができない(0,0)から始まり、そして2つだけに4段階のパスの先頭に戻る:の一つは、次のとおりです。(0,0)→(1,0) →(-1,1)→(0,1)→(0,0)、
そして、他のは、(0,0)→(0,1)→(1,1)→(1,0)→(0,0)。
あなたの仕事は、与えられた数N、MおよびM番目の障害物の分布のために、プログラミングがすべてのツアーパスを見つけることです。
入力
入力ファイルの最初の行は、Nステップのツアーコースを表す二つの整数N及びM、sight.inあります
数、およびMは、障害物の個数、前記0≤N≤40,0≤M≤50を表します。次のM行は、各列の座標を空間で分離された2つの隣接する整数の間に、二つの整数の障害物によって与えられます。
出力
- 一列のみ、見学ルートの要件を満たすために与えられた数sight.out出力ファイル。
サンプル入力
4 2
0 -1
1 0
サンプル出力
2
ソリューション:
検索は、剪定を必要としています。しかし、間違った質問を書く... ... 「残りの点を繰り返すことができない中で、」これらの言葉は表示されませんでした。しかし、最初の改正後に一点のみを得ました。アイデアは(ラインを考えるべきではない剪定)プルーニングすることを期待していなかったので、剪定は「裁判官は戻って最初にいくつかの手順を十分に持っていた後に行く場所」であるが、ステップ数をカウントし、ハードにプッシュしました長い時間のために(プログラムを参照)。しかし、第二の補正、または一点のみが完了した後。それから私は、マップが遅すぎますかしら?次いでアレイ動作の正の数のすべての存在、外の座標に翻訳。
そう:
負の数は、全体の翻訳を調整することができますがあります
これは、剪定枝刈りを検索することができます
STLは慎重にする必要があります
#include <iostream>
#include <cstdio>
#define maxn 2005
#define k 100 //平移系数
using namespace std;
int mp[maxn][maxn], need[maxn][maxn];
bool vis[maxn][maxn];
int t, n, ans;
int dx[5][3] = {
{0, 0, 0},
{0, 0, 0},
{0, 0, 0},
{0, 1, -1},
{0, -1, 1}
};
int dy[5][3] = {
{0, 0, 0},
{0, -1, 1},
{0, 1, -1},
{0, 0, 0},
{0, 0, 0}
};
inline int cal(int turn, int flag)
{
if(flag == 1)
{if(turn == 1) return 3; if(turn == 2) return 4; if(turn == 3) return 2; if(turn == 4) return 1;}
else
{if(turn == 1) return 4; if(turn == 2) return 3; if(turn == 3) return 1; if(turn == 4) return 2;}
return 0;
}
inline int call(int x, int y) {
x = abs(x - k), y = abs(y - k);
if((x % 2 == 0 && y % 2 == 0) || (x % 2 != 0 && y % 2 != 0)) return 2 * x;
else return 2 * (x - 1) + 1;
}
inline void dfs(int x, int y, int step, int turn)
{
if(mp[x][y] == -1) return;
if(!need[x][y]) need[x][y] = call(x, y);
if(step + need[x][y] > t + 1) return;
if(step > t)
{
if(x == k && y == k) {ans++; return;}
return;
}
int xx, yy;
xx = x + dx[turn][1], yy = y + dy[turn][1];
if(!vis[xx][yy])
{
vis[xx][yy] = 1;
dfs(xx, yy, step + 1, cal(turn, 1));
vis[xx][yy] = 0;
}
if(xx == k && yy == k && step == t) dfs(xx, yy, step + 1, cal(turn, 1));
xx = x + dx[turn][2], yy = y + dy[turn][2];
if(!vis[xx][yy])
{
vis[xx][yy] = 1;
dfs(xx, yy, step + 1, cal(turn, 2));
vis[xx][yy] = 0;
}
if(xx == k && yy == k && step == t) dfs(xx, yy, step + 1, cal(turn, 2));
}
int main()
{
freopen("sight.in", "r", stdin);
freopen("sight.out", "w", stdout);
vis[k][k] = 1;
cin >> t >> n;
for(int i = 1; i <= n; i++)
{
int x, y; cin >> x >> y;
mp[x + k][y + k] = -1;
}
vis[k][-1 + k] = 1, dfs(k, -1 + k, 2, 3), vis[k][-1 + k] = 0;
vis[k][1 + k] = 1, dfs(k, 1 + k, 2, 4), vis[k][1 + k] = 0;
vis[-1 + k][k] = 1, dfs(-1 + k, k, 2, 1), vis[-1 + k][k] = 0;
vis[1 + k][k] = 1, dfs(1 + k, k, 2, 2), vis[1 + k][k] = 0;
cout << ans;
return 0;
}
プライムパートナー
説明
- 両方の正の整数の場合と暗号化通信に適用することが可能と言われているように2と5、6および13のように、我々は「プライムパートナー」と呼んで素数、、、です。2,5,6,13、場合:今すぐパスワードは、たとえば、4つの正の整数があり、いくつかの正の整数nとなっている、いくつかのペアプライムパートナー」を選び出す、プログラムを設計スキームの様々な中から選択することを学びます2及び5,6及び13は、二つの「プライムパートナー」を取得成るスキームが呼び出されるまで、「プライムパートナー」 "で構成することができながら、図5及び図6は、「プライムパートナー」のセットを与えるためにグループに分けることができます。最善の解決策最善の解決策「もちろん、あなたが知りたいパスワードを学びます」。 "
入力
nが400以上でない正の整数n、prime.in入力ファイルの最初の行は、自然数の数を選択することを示しています。2行目は、空間を持つ2つの隣接するサブ番号との間ではなく、30,000以上のnは正の整数を返します
オープン。
出力
- 出力ファイルは、1行しかprime.outペアの数のフォームを取得した「プライムパートナー」を「ベストソリューション」を提供します。
サンプル入力
4
2 5 6 13
サンプル出力
2
ソリューション:
- 次のようにオリジナルのアイデアは、次のとおりです。
- 2と素数の数、および両側の偶数の場合
- でも完了した後、グラフが形成されています。
- この図は、実際には証拠が次の:(木です)
- Q A + C =、+ Bは、既知の素数、B + C =素数=
- 奇素数、A、B、それぞれ奇数及び偶数ため
- Aが奇数である場合にはC = A +偶数!=素数ように、Cの奇数は、導入することができます
- Aが偶数である場合にはC = A +偶数!=素数ように、Cの偶数は、導入することができます
- 結合の和で、A + C =数
- だから、図面の意味で、そこにはリングがありませんので、これはツリー図であります
- 次に図は、木の後ろにある、私はこの木の最長チェーンを取ることができ、答えは最長チェーン/ 2(切り捨て)
しかし、全体のバースト。
A = 1、B = 1、C =時刻1、A + C =プライム!これはそうそこに、図環上結論プッシュする矛盾する場合ため!
したがって、このアイデアは改善する必要があります。
二部グラフマッチングの正のソリューション:データが1でない場合は、その後、私のアルゴリズムが実現可能です。ハンガリーアルゴリズムの正のソリューションは、単一の変数に蓄積された、1そして、それがある場合は、1人のパートナーが、見つからない場合に奇数、偶数とのパートナーを見つけるために、その奇数側の全て、全てさえ反対側に、使用することができます。成功したペアリングの合計数、プラス2で割った不対1の総数は、答えです。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#define maxn 405
using namespace std;
int n, cnt1, cnt2, ans, tot;
int a[maxn], b[maxn], mat[maxn];
bool vis[maxn];
bool cal(int x, int y)
{
int t = x + y, last = (int)sqrt(t);
for(int i = 2; i <= last; i++)
if(t % i == 0) return 0;
return 1;
}
bool find(int x)
{
for(int i = 1; i <= cnt2; i++)
if(cal(a[x], b[i]) && !vis[i])
{
vis[i] = 1;
if(!mat[i] || find(mat[i]))
{
mat[i] = x;
return 1;
}
}
return 0;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
int t; cin >> t;
if(t % 2 == 0) b[++cnt2] = t;
else a[++cnt1] = t;
if(t == 1) tot++;
}
for(int i = 1; i <= cnt1; i++)
{
memset(vis, 0, sizeof(vis));
if(find(i))
{
ans++;
if(a[i] == 1) tot--;
}
}
cout << ans + (int)(tot / 2) << endl;
}