A.Red and Black (POJ1979)
网格搜索,用dfs或者bfs写都可以。
#include <cstdio>
#include <cstring>
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
int w,h;
char s[20][21];
bool vis[20][21];
int dfs(int x,int y) {
if (x<0||x>=h||y<0||y>=w||vis[x][y]||s[x][y]=='#')
return 0;
vis[x][y]=true;
int ret=1;
for (int i=0;i<4;++i)
ret+=dfs(x+dx[i],y+dy[i]);
return ret;
}
int main()
{
while (scanf("%d%d",&w,&h)==2&&w+h) {
for (int i=0;i<h;++i)
scanf("%s",s[i]);
memset(vis,0,sizeof vis);
for (int i=0;i<h;++i)
for (int j=0;j<w;++j)
if (s[i][j]=='@')
printf("%d\n",dfs(i,j));
}
return 0;
}
B.Grid (Codeforces Gym 100819O)
直接bfs就可以过了,步长由一格变成了格子里的值。
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define fst first
#define snd second
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
int n,m,d[500][500];
char s[500][500];
bool v[500][500];
queue<pii> que;
int main()
{
memset(d,0x3f,sizeof d);
scanf("%d%d",&n,&m);
for (int i=0;i<n;++i)
scanf("%s",s[i]);
que.push(pii(0,0));
d[0][0]=0;
v[0][0]=true;
while (!que.empty()) {
int x=que.front().fst,y=que.front().snd;
que.pop();
for (int i=0;i<4;++i) {
int tx=x+dx[i]*(s[x][y]-'0'),ty=y+dy[i]*(s[x][y]-'0');
if (tx<0||tx>=n||ty<0||ty>=m||v[tx][ty])
continue;
v[tx][ty]=true;
d[tx][ty]=d[x][y]+1;
que.push(pii(tx,ty));
}
}
if (d[n-1][m-1]==inf)
puts("IMPOSSIBLE");
else
printf("%d\n",d[n-1][m-1]);
return 0;
}
C.Battleships (UVA 11953)
理解了题意之后bfs就行。
#include <bits/stdc++.h>
using namespace std;
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
int t,n,res;
char s[100][101];
bool f;
void dfs(int x,int y) {
if (x<0||x>=n||y<0||y>=n||s[x][y]=='.')
return;
if (s[x][y]=='x')
f=true;
s[x][y]='.';
for (int i=0;i<4;++i)
dfs(x+dx[i],y+dy[i]);
}
int main()
{
scanf("%d",&t);
for (int cas=1;cas<=t;++cas) {
scanf("%d",&n);
for (int i=0;i<n;++i)
scanf("%s",s[i]);
res=0;
for (int i=0;i<n;++i)
for (int j=0;j<n;++j) {
f=false;
dfs(i,j);
res+=f;
}
printf("Case %d: %d\n",cas,res);
}
return 0;
}
D.Jailbreak (Codeforces Gym 100625J)
题目要求最少开门数,即由最基本的步数改成了其他标准,将普通队列改成优先队列维护一下开门的数目就行。
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int inf=0x3f3f3f3f;
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
struct cc {
int d,x,y;
cc(){}
cc(int d,int x,int y):d(d),x(x),y(y){}
bool operator<(const cc& c2)const {
return d>c2.d;
}
};
int t,n,m,pt,d[3][105][105];
long long res,tt;
char s[105][105];
bool vis[105][105];
priority_queue<cc> que;
void bfs(int xx,int yy) {
while (!que.empty())
que.pop();
que.push(cc(0,xx,yy));
memset(vis,0,sizeof vis);
vis[xx][yy]=true;
while (!que.empty()) {
int x=que.top().x,y=que.top().y,td=que.top().d;
que.pop();
d[pt][x][y]=td;
for (int i=0;i<4;++i) {
int tx=x+dx[i],ty=y+dy[i];
if (tx<0||tx>n||ty<0||ty>m||vis[tx][ty]||s[tx][ty]=='*')
continue;
vis[tx][ty]=true;
if (s[tx][ty]=='#')
que.push(cc(td+1,tx,ty));
else
que.push(cc(td,tx,ty));
}
}
}
int main()
{
scanf("%d",&t);
while (t--) {
pt=0;
memset(vis,0,sizeof vis);
scanf("%d%d",&n,&m);
memset(s,0,sizeof s);
memset(d,0x3f,sizeof d);
for (int i=1;i<=n;++i)
scanf("%s",s[i]+1);
++n;
++m;
for (int i=0;i<=n;++i)
s[i][m]=s[i][0]='.';
for (int i=0;i<=m;++i)
s[0][i]=s[n][i]='.';
for (int i=0;i<=n;++i)
for (int j=0;j<=m;++j)
if (s[i][j]=='$') {
bfs(i,j);
++pt;
}
bfs(0,0);
res=inf;
for (int i=0;i<=n;++i)
for (int j=0;j<=m;++j) {
tt=0;
for (int k=0;k<3;++k)
tt+=d[k][i][j];
if (s[i][j]=='#')
tt-=2;
res=min(res,tt);
}
printf("%lld\n",res);
}
return 0;
}
E.Phillip and Trains (Codeforces 586D)
搜索,将火车往左移等价于主人公往右移,注意状态的设计。
#include <cstdio>
#include <cstring>
int t, n, k;
char G[3][106];
bool flag, vis[3][105][3];
void dfs(int x, int y, int t) {
vis[x][y][t]=true;
if (y>=100) {
flag=true;
return;
}
if (t==0&&G[x][y+1]=='.'&&!vis[x][y+1][1])
dfs(x,y+1,1);
if (t==1) {
for (int i=-1; i<=1; ++i) {
if (x+i<0||x+i>2||vis[x+i][y][2])
continue;
if (G[x+i][y]=='.')
dfs(x+i,y,2);
}
}
if (t==2&&G[x][y+2]=='.'&&!vis[x][y+2][0])
dfs(x,y+2,0);
}
int main()
{
scanf("%d",&t);
while (t--) {
memset(vis, 0, sizeof vis);
scanf("%d%d%s%s%s",&n,&k,G[0],G[1],G[2]);
for (int i=0; i<3; ++i)
for (int j=n; j<105; ++j)
G[i][j]='.';
G[0][105]=G[1][105]=G[2][105]='\0';
flag=false;
for (int i=0; i<3; ++i)
if (G[i][0]=='s')
dfs(i,0,0);
if (flag)
puts("YES");
else
puts("NO");
}
return 0;
}
F.Biridian Forest (Codeforces 329B)
从终点bfs,如果主人公到终点的距离大于等于守卫到终点的距离,守卫可以在终点等主人公,则会引发一次对战。
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define fst first
#define snd second
typedef pair<int,int> pii;
const int inf=0x3f3f3f3f;
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
int r,c,d[1000][1000],sx,sy,res;
char s[1000][1001];
queue<pii> que;
void bfs(int xx,int yy) {
memset(d,0x3f,sizeof d);
que.push(pii(xx,yy));
d[xx][yy]=0;
while (!que.empty()) {
int x=que.front().fst,y=que.front().snd;
que.pop();
for (int i=0;i<4;++i) {
int tx=x+dx[i],ty=y+dy[i];
if (tx<0||tx>=r||ty<0||ty>=c||s[tx][ty]=='T'||d[tx][ty]!=inf)
continue;
d[tx][ty]=d[x][y]+1;
que.push(pii(tx,ty));
}
}
}
int main()
{
scanf("%d%d",&r,&c);
for (int i=0;i<r;++i)
scanf("%s",s[i]);
for (int i=0;i<r;++i)
for (int j=0;j<c;++j)
if (s[i][j]=='E')
bfs(i,j);
else if (s[i][j]=='S')
sx=i,sy=j;
for (int i=0;i<r;++i)
for (int j=0;j<c;++j)
if (s[i][j]>='0'&&s[i][j]<='9'&&d[i][j]<=d[sx][sy])
res+=s[i][j]-'0';
printf("%d\n",res);
return 0;
}
G.Irina Tornado (Codeforces Gym 100866I)
灌水法。按照题意建图,在图的外面刘处一圈,刚开始先灌水一遍,然后把墙砸了,再灌一遍水,两次的差值就是答案了。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
#define fst first
#define snd second
typedef pair<int, int> pii;
const int dx[4]={1,-1,0,0};
const int dy[4]={0,0,1,-1};
int n, m, x1, x2, y1, y2, res;
bool G[505][505][4], vis[505][505];
void bfs(int t) {
memset(vis, 0, sizeof vis);
queue<pii> que;
que.push(pii(0, 0));
while (!que.empty()) {
int x=que.front().fst, y=que.front().snd;
que.pop();
vis[x][y]=true;
res+=t;
for (int i=0; i<4; ++i) {
if (G[x][y][i])
continue;
int tx=x+dx[i], ty=y+dy[i];
if (tx<0||tx>=505||ty<0||ty>=505)
continue;
if (vis[tx][ty])
continue;
vis[tx][ty]=true;
que.push(pii(tx, ty));
}
}
}
void get(int n, bool ok) {
for (int i=0; i<n; ++i) {
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
if (x1==x2)
for (int i=min(y1, y2); i<max(y1, y2); ++i)
G[x1-1][i][0]=G[x1][i][1]=ok;
else
for (int i=min(x1, x2); i<max(x1, x2); ++i)
G[i][y1-1][2]=G[i][y1][3]=ok;
}
}
int main()
{
scanf("%d", &n);
res=0;
get(n, true);
bfs(-1);
scanf("%d", &m);
get(m, false);
bfs(1);
printf("%d\n", res);
return 0;
}
H.Comments (Codeforces 747E)
树形结构,维护一个全局指针,在树上dfs,最后按题意输出即可。
#include <cstdio>
#include <cstring>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
typedef unsigned int uii;
int n,ptr,op,cnt;
char s[1000005],t[50];
string str;
vector<string> vec[1000005];
int dfs(int p,int dep) {
str.clear();
while (s[p]!=',') {
str+=s[p];
++p;
}
vec[dep].push_back(str);
memset(t,0,sizeof t);
op=p;
++p;
while (s[p]!=','&&p<n)
++p;
for (int i=op+1;i<p;++i)
t[i-op-1]=s[i];
int sz;
sscanf(t,"%d",&sz);
for (int i=0;i<sz;++i)
p=dfs(p+1,dep+1);
return p;
}
int main()
{
scanf("%s",s);
n=strlen(s);
ptr=-1;
while (ptr<n)
ptr=dfs(ptr+1,0);
for (int i=0;i<n;++i)
if (vec[i].size()!=0)
++cnt;
else
break;
printf("%d\n",cnt);
for (int i=0;i<n;++i) {
if (vec[i].size()==0)
break;
for (uii j=0;j<vec[i].size();++j) {
cout<<vec[i][j];
printf("%c",j+1==vec[i].size()?'\n':' ');
}
}
return 0;
}
I.New Year and Fireworks (Codeforces 750D)
维护一下状态,可选择的一种方式是 位置、方向、第几次连锁反应 的笛卡尔积。
小技巧:后继方向的改变就是第7行注释里当前方向相邻的两个数,方便快速写出代码。
#include <bits/stdc++.h>
using namespace std;
const int dx[8]={-1,-1,-1,0,0,1,1,1};
const int dy[8]={-1,0,1,-1,1,-1,0,1};
const int d1[8]={1,0,1,0,2,3,5,4};
const int d2[8]={3,2,4,5,7,6,7,6};
/*
0 1 2
3 4
5 6 7
*/
int n,t[33],res;
bool vis[320][320][8][31],ok[320][320];
void dfs(int x,int y,int dir,int dep) {
if (vis[x][y][dir][dep]||dep>=n)
return;
vis[x][y][dir][dep]=true;
for (int i=0;i<t[dep];++i) {
x+=dx[dir];
y+=dy[dir];
ok[x][y]=true;
}
dfs(x,y,d1[dir],dep+1);
dfs(x,y,d2[dir],dep+1);
}
int main()
{
scanf("%d",&n);
for (int i=0;i<n;++i)
scanf("%d",&t[i]);
dfs(155,155,1,0);
for (int i=0;i<310;++i)
for (int j=0;j<310;++j)
if (ok[i][j])
++res;
printf("%d\n",res);
return 0;
}
J.Ancient Messages (UVA 1103)
水漫法,题目说了拓扑关系不会改变,是一个重要的提示,区别古文的方式就是里面有几个圈。
输入需要处理一下,剩下的用floodfill做一做就行了。
#include <bits/stdc++.h>
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
const char al[7]={"WAKJSD"};
using namespace std;
int w,h,t,cas;
char in[205][55];
bool s[205][205],vis[205][205];
void ffill(int x,int y) {
if (x<0||x>h||y<0||y>w||s[x][y])
return;
vis[x][y]=s[x][y]=true;
for (int i=0;i<4;++i)
ffill(x+dx[i],y+dy[i]);
}
int dfs(int x,int y) {
if (x<0||x>h||y<0||y>w||vis[x][y])
return 0;
int ret=0;
if (!s[x][y]) {
++ret;
ffill(x,y);
}
vis[x][y]=true;
for (int i=0;i<4;++i)
ret+=dfs(x+dx[i],y+dy[i]);
return ret;
}
int main()
{
while (scanf("%d%d",&h,&w)==2&&w+h) {
for (int i=1;i<=h;++i)
scanf("%s",in[i]+1);
memset(s,0,sizeof s);
memset(vis,0,sizeof vis);
for (int i=1;i<=h;++i)
for (int j=1;j<=w;++j) {
t=in[i][j]-'a'+10;
if (t<0)
t+='a'-'0'-10;
for (int k=0;k<4;++k)
s[i][((j-1)<<2)+4-k]=((t>>k)&1);
}
w<<=2;
++h;
++w;
dfs(0,0);
string str;
for (int i=1;i<h;++i)
for (int j=1;j<w;++j)
if (!vis[i][j])
str+=al[dfs(i,j)];
sort(str.begin(),str.end());
cout<<"Case "<<++cas<<": "<<str<<endl;
}
return 0;
}
K.Mixed Dimensions (Codeforces 100989N)
灌水法经典题。先将图的最外一圈入优先队列,作为进水点,按水位从低到高出队,每次出队,相当于将这一点作为水源,dfs四散开去,遇到比当前位置低的就灌满,遇到比当前位置高的入队作为新的水源。
#include <cstdio>
#include <queue>
using namespace std;
typedef long long ll;
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
struct tri {
int x,y,h;
tri(){}
tri(int x,int y,int h):x(x),y(y),h(h){}
bool operator<(const tri& t)const {
return h>t.h;
}
};
int r,c;
ll res,g[505][505];
bool vis[505][505];
priority_queue<tri> que;
void dfs(tri t) {
vis[t.x][t.y]=true;
for (int i=0;i<4;++i) {
int tx=t.x+dx[i],ty=t.y+dy[i];
if (tx<0||tx>=r||ty<0||ty>=c||vis[tx][ty])
continue;
if (g[tx][ty]<=t.h) {
res+=(t.h-g[tx][ty]);
dfs(tri(tx,ty,t.h));
} else
que.push(tri(tx,ty,g[tx][ty]));
}
}
int main()
{
scanf("%d%d",&r,&c);
for (int i=0;i<r;++i)
for (int j=0;j<c;++j) {
scanf("%lld",&g[i][j]);
if (!i||!j||i==r-1||j==c-1)
que.push(tri(i,j,g[i][j]));
}
while (!que.empty()) {
tri t=que.top();
if (!vis[t.x][t.y])
dfs(que.top());
que.pop();
}
printf("%lld\n",res);
return 0;
}
L.9 Puzzles (UVA 11513)
同8数码问题。这题多个询问,可以反向打表。
用到了一个完美哈希函数,康托展开,还原字符串的时候用到了康托逆展开。
参考链接:http://baike.baidu.com/link?url=KJkB832n07XD9Zuzf1hv9s9ziV38nOGBES1T0oGUOMPadXIdK7XnPwL_nZ05Zf1-N-5rHn0pIrmweeWSaOLeveJZ6tiGoktL7XaDTIcFCV_WzO7h9Xvwz-8MWuPFkpab
#include <bits/stdc++.h>
using namespace std;
const char a1[4]={"123"};
const char a2[3]={"HV"};
struct ss {
string op;
int fa;
}res[362881];
string s1,s2,in,r;
queue<int> que;
queue<char> q2;
int fac[10],h1,d,h2,t,c;
bool vis[10];
void pre() {
fac[0]=1;
for (int i=1;i<=9;++i)
fac[i]=i*fac[i-1];
}
int get(string s) {
int ret=1;
for (int i=0;i<9;++i) {
int c=0;
for (int j=i+1;j<9;++j)
if (s[j]<s[i])
++c;
ret+=c*fac[8-i];
}
return ret;
}
string dec(int u) {
--u;
memset(vis,0,sizeof vis);
string ret;
for (int i=0;i<9;++i) {
d=u/fac[8-i]+1;
int j;
for (j=0;d;++j)
if (!vis[j])
--d;
--j;
vis[j]=true;
ret+=(j+'1');
u%=fac[8-i];
}
return ret;
}
string shift(int x,int y) {
string ret=s1;
if (y==0) {
swap(ret[x*3],ret[x*3+1]);
swap(ret[x*3+1],ret[x*3+2]);
} else {
swap(ret[x],ret[6+x]);
swap(ret[3+x],ret[6+x]);
}
return ret;
}
void bfs() {
h1=get("123456789");
res[h1].fa=-1;
que.push(h1);
while (!que.empty()) {
h1=que.front();
que.pop();
s1=dec(h1);
for (int i=0;i<3;++i)
for (int j=0;j<2;++j) {
s2=shift(i,j);
h2=get(s2);
if (res[h2].fa)
continue;
res[h2].fa=h1;
res[h2].op=a2[j];
res[h2].op+=a1[i];
que.push(h2);
}
}
}
void solve() {
while (true) {
in="";
for (int i=0;i<9;++i) {
scanf("%d",&t);
if (!t)
return;
in+=t+'0';
}
h1=get(in);
if (!res[h1].fa)
puts("Not solvable");
else {
r="";
while (res[h1].fa!=-1) {
q2.push(res[h1].op[0]);
q2.push(res[h1].op[1]);
h1=res[h1].fa;
}
if (!q2.size())
puts("0");
else {
printf("%d ",int(q2.size()>>1));
while (!q2.empty()) {
putchar(q2.front());
q2.pop();
}
putchar('\n');
}
}
}
}
int main()
{
pre();
bfs();
solve();
return 0;
}
M.Editing a Book (UVA 11212)
IDA*。因为每一层的状态数很多,且最大深度不深,仅为n-1,故可以考虑迭代加深搜索。
启发函数推导:在一个有序的排列中,一定满足ai+1-ai=1,则我们令不满足这个关系式的ai+1的个数为cnt,若当前迭代到d层,总迭代层数是tm层,则还可以进行tm-d次操作,每次操作最多能使3个数改变后继关系,所以若(tm-d)*3<cnt。则说明最好的情况下,也不可能将序列恢复成顺序排列,可以剪纸。
#include <cstdio>
#include <iostream>
#include <string>
using namespace std;
int n,a,m,cas;
string s,g;
bool dfs(int d,string s) {
int cnt=0;
for (int i=1;i<n;++i)
if (s[i]!=s[i-1]+1)
++cnt;
if (!cnt)
return true;
if ((m-d)*3<cnt)
return false;
string a,b,c,e,s1;
for (int i=0;i<n;++i)
for (int j=i+1;j<=n;++j)
for (int k=0;k<i;++k) {
a=s.substr(0,k);
b=s.substr(i,j-i);
c=s.substr(k,i-k);
e=s.substr(j,n-j);
if (dfs(d+1,a+b+c+e))
return true;
}
return false;
}
int main()
{
while (scanf("%d",&n)==1&&n) {
s.clear();
g.clear();
for (int i=1;i<=n;++i) {
scanf("%d",&a);
s+=char(a+'0');
g+=char(i+'0');
}
m=0;
while (true) {
if (dfs(0,s))
break;
++m;
}
printf("Case %d: %d\n",++cas,m);
}
return 0;
}
N.Marble Game (UVA 1063)
Dead do.
用map记录一下已经遍历到的状态以及路径长度即可。
#include <cstdio>
#include <vector>
#include <cstring>
#include <map>
#include <queue>
using namespace std;
const int dx[4]={0,0,-1,1};
const int dy[4]={-1,1,0,0};
typedef vector<vector<int> > vvi;
int n,m,W,g[4][4],x1,y1,x2,y2,cas,res;
bool w[4][4][4][4],f;
vvi vec(4),tv(4),nv(4);
map<vvi,int> mp;
queue<vvi> que;
vvi slip(int i,int x,int y,vvi v) {
while (true) {
int tx=x+dx[i],ty=y+dy[i];
if (tx<0||ty<0||tx>=n||ty>=n||w[tx][ty][x][y]||(v[tx][ty]&&v[tx][ty]<=m))
break;
if (v[tx][ty]-v[x][y]==m) {
v[tx][ty]=v[x][y]=0;
break;
}
if (v[tx][ty]>m) {
f=true;
return v;
}
swap(v[x][y],v[tx][ty]);
x=tx;
y=ty;
}
return v;
}
vvi turn(int id,vvi v) {
if (!(id&1)) {
for (int i=0;i<n;++i)
for (int j=0;j<n;++j)
if (v[i][j]&&v[i][j]<=m)
v=slip(id,i,j,v);
} else {
for (int i=n-1;i>=0;--i)
for (int j=n-1;j>=0;--j)
if (v[i][j]&&v[i][j]<=m)
v=slip(id,i,j,v);
}
return v;
}
void print(vvi v) {
for (int i=0;i<n;++i)
for (int j=0;j<n;++j)
printf("%d%c",v[i][j],j+1==n?'\n':' ');
}
void bfs() {
mp.clear();
que.push(vec);
mp[vec]=1;
while (!que.empty()) {
nv=que.front();
que.pop();
for (int i=0;i<4;++i) {
f=false;
tv=turn(i,nv);
if (f)
continue;
if (mp.find(tv)!=mp.end())
continue;
mp[tv]=mp[nv]+1;
que.push(tv);
}
}
}
int main()
{
while (scanf("%d%d%d",&n,&m,&W)==3&&n+m+W) {
memset(g,0,sizeof g);
memset(w,0,sizeof w);
for (int i=1;i<=m;++i) {
scanf("%d%d",&x1,&y1);
g[x1][y1]=i;
}
for (int i=1;i<=m;++i) {
scanf("%d%d",&x1,&y1);
g[x1][y1]=g[x1][y1]?0:i+m;
}
for (int i=0;i<4;++i)
vec[i].clear();
for (int i=0;i<n;++i)
for (int j=0;j<n;++j)
vec[i].push_back(g[i][j]);
for (int i=0;i<W;++i) {
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
w[x1][y1][x2][y2]=true;
w[x2][y2][x1][y1]=true;
}
bfs();
for (int i=0;i<n;++i) {
vec[i].clear();
for (int j=0;j<n;++j)
vec[i].push_back(0);
}
printf("Case %d: ",++cas);
if (mp.find(vec)==mp.end())
puts("impossible\n");
else
printf("%d moves\n\n",mp[vec]-1);
}
return 0;
}
O.Gears (Codeforces Gym 100819V)
题意看起来很吓人,仔细看一下题目中的齿轮密度无限大的提示,发现其实没有那么复杂。
性质:
1.齿轮连接处线速度是一样的,角速度则是半径之比的倒数。
2.所以如果从起点出发,有边为奇数的圈的话,第0号齿轮不能转动。
3.0号齿轮和n-1号齿轮不连通,则不能带动n-1号齿轮转动。
解法:
建图:相切的圆之间连边,代表齿轮接触。
以0号齿轮为起点染色判断是否是二分图。不是的话证明有奇圈,非法。
是二分图则判断终点是否被染色:
若没有,则不能带动终点齿轮转动;
若有且颜色相同,则同向转;若颜色相反,则反向转。
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef unsigned int uii;
int n,x[1000],y[1000],r[1000],gcd,col[1000];
vector<int> vec[1000];
inline int sqr(int x) {
return x*x;
}
int check(int i,int j) {
return sqr(r[i]+r[j])==sqr(x[i]-x[j])+sqr(y[i]-y[j]);
}
bool dfs(int u,int co) {
col[u]=co;
for (uii i=0;i<vec[u].size();++i) {
int v=vec[u][i];
if (col[v]) {
if (col[u]==col[v])
return false;
continue;
}
if (!dfs(v,-1*co))
return false;
}
return true;
}
int main()
{
scanf("%d",&n);
memset(col,0,sizeof col);
for (int i=0;i<n;++i) {
scanf("%d%d%d",&x[i],&y[i],&r[i]);
vec[i].clear();
}
for (int i=0;i<n;++i)
for (int j=i+1;j<n;++j)
if (check(i,j)) {
vec[i].push_back(j);
vec[j].push_back(i);
}
if (!dfs(0,1))
puts("The input gear cannot move.");
else if (!col[n-1])
puts("The input gear is not connected to the output gear.");
else {
gcd=__gcd(r[0],r[n-1]);
if (col[0]!=col[n-1])
putchar('-');
printf("%d:%d\n",r[0]/gcd,r[n-1]/gcd);
}
return 0;
}