例 - ネットワーク パスファインディング
トピックの背景
X 国のネットワークは、複数の回線を使用して複数のノードを接続しています。ノード間の通信は双方向です。安全上の理由から、重要なデータ パケットは宛先に到達するために正確に 2 回転送する必要があります。パケットはどのノードでも生成される可能性があり、ネットワーク内に異なる転送パスがいくつあるかを知る必要があります。
送信元アドレスと宛先アドレスは同じであってもかまいませんが、中間ノードは異なっている必要があります。
以下の図に示すネットワークです。
1 -> 2 -> 3 -> 1 が許可されます
1 -> 2 -> 1 -> 2 または 1 -> 2 -> 3 -> 2 は不正です。
入力フォーマット
入力データの最初の行は 2 つの整数 NM で、それぞれノードの数と接続線の数を表します (1<=N<=10000; 0<=M<=100000)。
次に M 行があり、各行には 2 つの整数 u と v が含まれており、ノード u と v が接続されていることを示します (1<=u、v<=N、u!=v)。
入力データは、任意の 2 点が最大 1 つのエッジによって接続されていること、および自己接続エッジがないこと、つまり複数のエッジや自己ループがないことを保証します。
出力フォーマット
要件を満たすパスの数を示す整数を出力します。
入力サンプルと出力サンプル
入力サンプル
3 3 1 2 2 3 1 3
出力サンプル
6
参照コード
#include <iostream>
#include <cstring>
using namespace std;
#define MAXN 10005
#define MAXM 100005
struct node{
int to,next;
}edge[MAXM];
int head[MAXN];
int cnt,sum;
void add(int a,int b)
{
node E={b,head[a]};
edge[cnt]=E;
head[a]=cnt++;
}
void dfs(int from,int to,int num)
{
if (num==3)
{
sum++;
return;
}
for (int i=head[to];i!=-1;i=edge[i].next)
{
int v=edge[i].to;
if (v!=from)
{
dfs(to,v,num+1);
}
}
}
int main()
{
int n,m,a,b;
while (cin>>n>>m)
{
cnt=0;sum=0;
memset(head,-1,sizeof(head));
for (int i=0;i<m;i++)
{
cin>>a>>b;
add(a,b);
add(b,a);
}
for (int i=1;i<=n;i++)
dfs(i,i,0);
cout<<sum<<endl;
}
return 0;
}
ある事例から他の事例への推論を引き出す——著名な僧侶の戦い
トピックの背景
古代の葬儀では、著名な僧侶が儀式を行うために招待されることがよくありました。式典の後は、憂鬱な雰囲気を和らげるために、「名僧の格闘技」などの興味深いプログラムが開催されることもあります。
プログラムの一般的な手順は次のとおりです。まず、穀物 (通常は米) を使用して、地面にいくつかの階段 (N レベルの塔を表す) を「描画」します。数人の若い僧侶がランダムに特定の段差に「立っています」。人は最も高い段に立つ必要があり、それ以外は任意です。(図1に示すように)
ゲームに参加している二人の魔術師は若い僧侶に何段でも上がれと命令しますが、高い段にいる若い僧侶に阻まれて渡ることができません。二人の若い僧侶が同じ段に立つことも、下の段に移動することもできません。
二人の魔術師が交代で指示を出し、最終的には必然的に若い僧侶全員が高い階段に群がり、上がれなくなる。魔術師が指揮を執る番になり、動き続けることができなくなった場合、ゲームは終了し、魔術師は敗北を認めます。
既知の歩数と若い僧侶の配置位置について、最初に命令を出した魔術師が勝利を確実にするためにどのような判断を下すべきかを計算してください。
入力フォーマット
入力データはスペースで区切られた N 個の整数の行であり、小さな僧侶の位置を示します。歩数は1から始まるので、最後の小僧の位置が総歩数となります。(N<100、総ステップ数<1000)
出力フォーマット
出力は 1 行にスペースで区切られた 2 つの整数です: AB。これは、位置 A にある小さな僧侶を位置 B に移動することを意味します。解が複数ある場合はAの値が小さい方の解を出力し、解がない場合は-1を出力します。
入力サンプルと出力サンプル
入力サンプル
1 5 9
出力サンプル
1 4
参照コード
#include <iostream>
#include <cstdio>
#include <sstream>
using namespace std;
int mp[100],sub[100],c;
int main() {
string s;
getline(cin,s);
istringstream in(s);
int t = 0;
while(in >> mp[c ++]) {
if(c > 1) {
sub[c - 2] = mp[c - 1] - mp[c - 2] - 1;
if(c % 2 == 0) t ^= sub[c - 2];
}
}
if(!t) {
printf("-1\n");
}
else {
for(int i = 0;i < c - 1;i ++) {///枚举每个人
for(int j = 1;j < mp[i + 1] - mp[i];j ++) {///移动步数
sub[i] -= j;
if(i) sub[i - 1] += j;
t = 0;
for(int k = 0;k < c - 1;k += 2) {
t ^= sub[k];
}
if(t == 0) {
printf("%d %d",mp[i],mp[i] + j);
break;
}
sub[i] += j;
if(i) sub[i - 1] -= j;
}
}
}
}