7674
题意:n个人(0~n-1)坐成一圈,有p个石头,从第0个人开始,如果还有石头,那么他从中取出一个,如果没有石头,那么他把自己所有的石头贡献出来,接着轮到下一个,问最后p个石头会到谁那去。
思路:简单模拟即可。
#include <cstdio>
#include <cstring>
int n, p, arr[55], curP, curN;
int main()
{
while (true)
{
scanf("%d%d",&n,&p);
if (n == 0 && p == 0) break;
memset(arr, 0, sizeof(arr));
curN = p;
curP = 0;
while (true)
{
if (arr[curP] == p) break;
else if (curN > 0)
{
curN --;
arr[curP] ++;
}
else
{
curN = arr[curP];
arr[curP] = 0;
}
curP = (curP+1) % n;
}
printf("%d\n", curP);
}
}
7675
题意:求联通块的数目
思路:广搜深搜皆可
#include <cstdio>
#include <queue>
using namespace std;
int w, h, ans;
bool g[55][55];
int dir[8][2] = {{-1,-1},{-1,0},{-1,1},{0,1},{0,-1},{1,-1},{1,0},{1,1}};
struct Point
{
int r, c;
Point() {}
Point(int _r, int _c): r(_r), c(_c) {}
Point next(int k) { return Point(r+dir[k][0], c+dir[k][1]); }
bool leagal() { return r>=0 && r<h && c>=0 && c<w && g[r][c]==1; }
void setSea() { g[r][c] = 0; }
} cur, nxt;
queue <Point> Q;
int main()
{
while (true)
{
scanf("%d%d",&w,&h);
if (w == 0 && h == 0) break;
for (int i = 0; i < h; ++ i)
for (int j = 0; j < w; ++ j)
scanf("%d",&g[i][j]);
ans = 0;
for (int i = 0; i < h; ++ i)
{
for (int j = 0; j < w; ++ j)
{
if (g[i][j] == 1)
{
ans ++;
cur = Point(i,j);
cur.setSea();
Q.push(cur);
while (!Q.empty())
{
cur = Q.front();
Q.pop();
for (int k = 0; k < 8; ++ k)
{
nxt = cur.next(k);
if (nxt.leagal())
{
nxt.setSea();
Q.push(nxt);
}
}
}
}
}
}
printf("%d\n", ans);
}
}
7691
题意:给一个字母的等式,每个字母代表不同的数字,每个数字被不同的字母代表着,不能有除零外的以零打头的数,问有多少种字母的复制方法。
思路:记录每一个字母的权值,(在十位的字母权值+10,类推)。然后深搜,注意打头的字母不能为零的情况。这样暴力深搜会超时(我做的时候是超时了)。加一个非常简单的剪枝,就是在搜之前判断当前最大和最小的可能值,如果最大值也比零小或者最小值也比零大,那么不必再搜索下去。
#include <cstdio>
#include <cstdlib>
#include <cstring>
char s[15];
int n, c[30], l, ans;
int data[30], numb[30];
bool used[30], frst[30], vis[15];
void dfs(int d, int sum)
{
int x = sum;
for (int i = d; i < l; ++ i)
if (c[data[i]] > 0) x += c[data[i]] * 9;
if (x < 0) return ;
x = sum;
for (int i = d; i < l; ++ i)
if (c[data[i]] < 0) x += c[data[i]] * 9;
if (x > 0) return ;
if (d == l)
{
if (sum == 0) ans ++;
return ;
}
for (int i = 0; i < 10; ++ i) if (!vis[i])
{
if (frst[data[d]] == 1 && i == 0) continue;
numb[d] = i;
vis[i] = true;
dfs(d+1, sum+c[data[d]]*i);
vis[i] = false;
}
}
int main()
{
while (scanf("%d", &n), n)
{
memset(used, false, sizeof(used));
memset(frst, false, sizeof(frst));
memset(c, 0, sizeof(c));
for (int i = 0; i < n; ++ i)
{
scanf("%s", s);
l = strlen(s);
if (l > 1) frst[s[0]-'A'] = true;
for (int j = l-1, pow10 = 1; j >= 0; -- j, pow10 *= 10)
{
used[s[j]-'A'] = true;
c[s[j]-'A'] += ((i==n-1) ? (-pow10) : pow10);
}
}
l = 0;
for (int i = 0; i < 26; ++ i)
if (used[i]) data[l++] = i;
ans = 0;
dfs(0, 0);
printf("%d\n", ans);
}
}
7692
题意:给一个n个城市m条路径(有速度上限,有权值)的无向图,给出起点终点,每经过一个城市,速度可以+1,+0,-1,问从起点到终点的最短时间。
思路:直接广搜,可以用优先队列,速度上限最大不过30,城市最多不过30个,很好判重。值得注意的题目的一个信息是:不能走U字型的路,被这个坑了很多时间,也就是不能1-2-1这样走。
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
#define INF 1e20
#define N 55
struct Edge
{
int ed, dist, limit;
Edge() {}
Edge(int _e, int _d, int _l): ed(_e), dist(_d), limit(_l) {}
};
vector <Edge> adj[N];
double best[N][N][N];
bool visit[N][N][N];
int n, m, s, e;
struct Node
{
int preP, curP, v;
double t;
Node() {}
Node(int _pp, int _cp, int _v, double _t): preP(_pp), curP(_cp), v(_v), t(_t) {}
bool operator < (const Node &obj) const { return t > obj.t;}
}cur, nxt;
bool bfs()
{
priority_queue <Node> Q;
Q.push(Node(s,s,0,0));
best[s][0][s] = 0;
while (!Q.empty())
{
cur = Q.top();
Q.pop();
if (visit[cur.curP][cur.v][cur.preP]) continue;
else visit[cur.curP][cur.v][cur.preP] = true;
if (cur.curP==e && cur.v==1)
{
printf("%.5lf\n", cur.t);
return true;
}
nxt.preP = cur.curP;
for (int i = adj[cur.curP].size()-1; i >= 0; -- i)
{
nxt.curP = adj[cur.curP][i].ed;
if (nxt.curP == cur.preP) continue;
for (int dv = -1; dv <= 1; ++ dv)
{
nxt.v = cur.v+dv;
if (!visit[nxt.curP][nxt.v][nxt.preP] && nxt.v>0 && nxt.v<=adj[cur.curP][i].limit)
{
nxt.t = cur.t + adj[cur.curP][i].dist*1.0/nxt.v;
if (best[nxt.curP][nxt.v][nxt.preP] > nxt.t)
{
best[nxt.curP][nxt.v][nxt.preP] = nxt.t;
Q.push(nxt);
}
}
}
}
}
return false;
}
int main()
{
while (scanf("%d%d",&n,&m) != EOF)
{
if (n==0 && m==0) break;
scanf("%d%d",&s,&e);
for (int i = 0; i < N; ++ i)
{
adj[i].clear();
for (int j = 0; j < N; ++ j)
{
for (int k = 0; k < N; ++ k)
{
visit[i][j][k] = false;
best[i][j][k] = INF;
}
}
}
for (int i=0,u,v,d,c; i < m; ++ i)
{
scanf("%d%d%d%d",&u,&v,&d,&c);
adj[u].push_back(Edge(v,d,c));
adj[v].push_back(Edge(u,d,c));
}
if (!bfs()) puts("unreachable");
}
}
7693
题意:给两堆数{X},{Y},如果{X}中的某个数和{Y}中的某个数的GCD大于1,那么称这两个数可以配对,问最多有多少个配对。
思路:赤裸裸的二分图匹配问题。
#include <cstdio>
#include <cstring>
#define N 505
int nx, ny;
int cx[N], cy[N];
bool bmap[N][N];
bool bmask[N];
bool gcd(int a, int b)
{
int mod;
while (mod = a % b)
{
a = b;
b = mod;
}
return b > 1;
}
int findPath(int u)
{
for (int i = 0; i < ny; ++ i)
{
if (bmap[u][i] && !bmask[i])
{
bmask[i] = 1;
if (cy[i] == -1 || findPath(cy[i]))
{
cy[i] = u;
cx[u] = i;
return 1;
}
}
}
return 0;
}
int maxMatch()
{
int res = 0;
memset(cx, -1, sizeof(cx));
memset(cy, -1, sizeof(cy));
for (int i = 0; i < nx; ++ i)
{
if (cx[i] == -1)
{
memset(bmask, 0, sizeof(bmask));
res += findPath(i);
}
}
return res;
}
int main()
{
while (true)
{
scanf("%d%d",&nx,&ny);
if (nx == 0 && ny == 0) break;
memset(bmap, 0, sizeof(bmap));
for (int i = 0; i < nx; ++ i)
scanf("%d", &cx[i]);
for (int i = 0; i < ny; ++ i)
{
scanf("%d", &cy[i]);
for (int j = 0; j < nx; ++ j)
{
if (gcd(cy[i], cx[j]))
bmap[j][i] = 1;
}
}
printf("%d\n", maxMatch());
}
}