B.フォックスとミニマルパス
テストごとの制限時間
1秒
テストごとのメモリ制限
256メガバイト
入力
標準入力
出力
標準出力
Fox Cielは、プログラミングコンテストのタスクを書きたいと考えています。タスクは次のとおりです。「n個の 頂点を持つ単純な無向グラフが与えられ ます。各エッジの単位長があります。頂点1と頂点2の間の最短経路の数を計算する必要があります。」
一部の作家と同じように、彼女は特定の出力を使用して例を作成したいと考えています。たとえば、誕生日やボーイフレンドの数などです。彼女がkに正確に等しい答えでテストケースを作るのを手伝ってくれ ませんか?
入力
最初の行は、単一の整数含ま K (1つの≤ K ≤109)。
出力
もし出力グラフべき G と n個の 頂点(2≤ N ≤1000)。 グラフの頂点1と頂点2の間には正確にk個の最短経路が必要 です。
最初の行には整数nが含まれている必要があります 。次いで、隣接行列 G と N 行と N 列が従わなければなりません。行列の各要素は「N」または「Y」でなければなりません。場合 G ijは 「Y」であり、次いで、グラフ Gは 頂点接続エッジ有し I と頂点 jは。グラフの頂点に1からnまでの番号が付けられているとし ます。
グラフ無向と簡単されなければならない: G II = 'N'及び G IJ = G jiを 保持しなければなりません。また、頂点1と頂点2の間に少なくとも1つのパスが必要です。答えが存在することが保証されています。正解が複数ある場合は、どれでも出力できます。
例
入力
コピー
2
出力
コピー
4
NNYY
NNYY
YYNN
YYNN
入力
コピー
9
出力
コピー
8
NNYYYNNN
NNNNNYYY
YNNNNYYY
YNNNNYYY
YNNNNYYY
NYYYYNNN
NYYYYNNN
NYYYYNNN
入力
コピー
1
出力
コピー
2
NY
YN
注意
最初の例では、1-3-2と1-4-2の2つの最短パスがあります。
2番目の例では、9つの最短パスがあります:1-3-6-2、1-3-7-2、1-3-8-2、1-4-6-2、1-4-7-2、 1-4-8-2、1-5-6-2、1-5-7-2、1-5-8-2。
本旨:
数値Kを入力して、K個の最短パスを持つ1から2までの無向グラフを作成します。ポイントの総数は、1000を超えません。
解決:
Kを複数のバイナリ桁に分割した後、各秒のパワーバーの最短パスは次のように表すことができます。
この図はK = 4の場合を示しているため、ループが追加されるたびに、答えは* 2になります。この図のK = 6の場合、次のように、対応するバイナリビットからエンドポイントまでのパスを追加します。
最短パスの長さは最大分割2桁* 2に等しく、残りの2桁はポイントを直接追加するのに十分な長さではありません。
受け入れられたコード
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 1e3 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }
vector <int> ver;
int bit[30]; // 记录相应二进制位的点编号
bool G[N][N];
void Add(int u, int v) {
G[u][v] = G[v][u] = true;
}
int main()
{
int k;
cin >> k;
if (k == 1) {
puts("2"), puts("NY"), puts("YN");
exit(0);
}
else if (k == 2) {
puts("4");
puts("NNYY"), puts("NNYY");
puts("YYNN"), puts("YYNN");
exit(0);
}
else if (k == 3) {
puts("5");
puts("NNYYY"), puts("NNYYY");
puts("YYNNN"), puts("YYNNN");
puts("YYNNN"), exit(0);
} // 特判一些不好处理的情况
int pos = 0; // 拆分二进制位
while (k) {
if (k & 1)
ver.push_back(pos);
k >>= 1;
pos++;
}
int len = ver.back();
int cnt = 2;
int u = cnt; // 初始化最长的
for (int i = 1; i <= len; i++) {
if (i == 1) {
bit[i - 1] = 1;
Add(1, ++cnt), Add(1, ++cnt);
cnt++;
Add(cnt - 1, cnt), Add(cnt - 2, cnt);
u = cnt;
}
else if (i == len) {
bit[i - 1] = u;
Add(u, ++cnt), Add(u, ++cnt);
Add(cnt - 1, 2), Add(cnt, 2);
}
else {
bit[i - 1] = u;
Add(u, ++cnt), Add(u, ++cnt);
cnt++;
Add(cnt - 1, cnt), Add(cnt - 2, cnt);
u = cnt;
}
}
for (int i = 0; i < SZ(ver) - 1; i++) { // 最长以外的二进制位
int u = bit[ver[i]]; // 点编号
int lst = 2 * (len - ver[i]);
for (int j = 1; j <= lst; j++) { // 添加的点数
if (j == lst)
Add(u, 2);
else
Add(u, ++cnt), u = cnt;
}
}
cout << cnt << endl;
for (int i = 1; i <= cnt; i++) {
for (int j = 1; j <= cnt; j++) {
if (G[i][j])
printf("Y");
else
printf("N");
}
puts("");
}
return 0; // 改数组大小!!!用pair记得改宏定义!!!
}