A
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int INF = 1e6;
int a, b, c;
int main()
{
while(cin >> a >> b >> c) {
int maxP = max(a, max(b, c));
int minP = min(a, min(b, c));
int ans = INF;
for(int i = minP; i <= maxP; i++) {
int dis = 0;
dis += abs(a - i);
dis += abs(b - i);
dis += abs(c - i);
ans = min(ans, dis);
}
cout << ans << endl;
}
return 0;
}
B
#include <iostream>
#include <cstdio>
#include <ctype.h>
using namespace std;
const int maxn = 300;
const int INF = 1e6;
char str[maxn];
int n;
int main()
{
//freopen("in.txt", "r", stdin);
while(~scanf("%d", &n)) {
scanf("%s", str);
int inside_ = 0, len = 0;
bool inPar = false;
bool isWord = false;
int tmp = 0;
for(int i = 0; i < n; i++) {
if(isalpha(str[i])) {
if(!isWord) isWord = true;
if(!inPar) tmp++;
if(i == n-1 && isWord && !inPar) {
len = max(len, tmp);
tmp = 0;
}
}
if(!isalpha(str[i])) {
//printf("not alpha:");
if(isWord && !inPar) {
isWord = false;
len = max(len, tmp);
tmp = 0;
//printf("isWord && !inPar");
}
if(isWord && inPar) {
isWord = false;
inside_++;
//printf("isWord && inPar");
}
if(str[i] == '(') {
inPar = true;
//printf("(\n");
}
if(str[i] == ')') {
inPar = false;
//printf(")\n");
}
}
}
printf("%d %d\n", len, inside_);
}
return 0;
}
/*
contest id:723
translation:
给出一张表演名单a[i],表示第i首歌是由编号为a[i]的乐队演唱的。设编号为i的乐队演唱的总歌曲数目为b[i]。
现在给出m的值,可以将名单上任意一支乐队替换成另外任意一只乐队,要求一种替换方法使得min(b[1],...,b[m])
最大。并给出最后的符合要求的名单。
solution:
贪心
要求min(b[1],...b[m])最大,可想而知最后的整个名单上的乐队肯定都是1~m的乐队,且min(b[1],...,b[m])
的值肯定为n/m。所以利用贪心法,先将编号大于m的一支乐队替换成1~m中b值最小的乐队,如此反复直到名单上没有
编号大于m的乐队,如果这个时候b值最小的还是小于n/m的话,就再选出一个b值最大的替换成b值最小的。直到满足
min(b[1]...b[m])==n/m为止。
note:
date: 2016.10.4
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>
using namespace std;
const int maxn = 2000 + 5;
struct Node {
int songs, band;
Node(int s, int b):songs(s), band(b) {}
Node(){}
bool operator < (const Node& rhs) const {
if(songs == rhs.songs) return band < rhs.band;
else return songs > rhs.songs;
}
};
int n, m, maxId;
int a[maxn];
map<int, int> b;
void setList(int id, int res) {
if(res > 0) {
for(int i = 1; i <= n; i++) if(a[i] > m) {
b[a[i]]--;
a[i] = id;
break;
}
} else {
int maxNum = -1, id1;
map<int, int>::iterator it;
for(it = b.begin(); it != b.end(); it++) {
if(it->second > maxNum) {
maxNum = it->second;
id1 = it->first;
}
}
for(int i = 1; i <= n; i++) if(a[i] == id1) {
b[a[i]]--;
a[i] = id;
break;
}
}
}
int main()
{
//freopen("in.txt", "r", stdin);
while(cin >> n >> m) {
memset(a, 0, sizeof(a));
b.clear();
int res = 0; //m+1 ~ n
priority_queue<Node> pq;
for(int i = 1; i <= n; i++) {
cin >> a[i];
b[a[i]]++;
if(a[i] > m) res++;
}
for(int i = 1; i <= m; i++) {
pq.push(Node(b[i], i));
}
int op = 0; int standar = n / m;
int ans;
while(!pq.empty()) {
Node x = pq.top(); pq.pop();
int band = x.band; int song = x.songs;
if(song >= standar) { ans = song; break; }
setList(band, res);
song++; op++; res--;
pq.push(Node(song, band));
}
printf("%d %d\n", ans, op);
printf("%d", a[1]);
for(int i = 2; i <= n; i++) printf(" %d", a[i]);
printf("\n");
}
return 0;
}
D
/*
contest id:723
translation:
一张地图上有水方块和土方块,且这张地图被海洋所包括。边界上与海洋临界的水方块视作海洋的一部分。
相邻水方块的集合称作一个池塘。要求将一些水方块变成土方块使得池塘的数量为k。最少需要转换几个
水方块。并打印出最后的地图。
solution:
dfs,贪心
简单的floodfill即可。floodfill与海洋临界的水方块,做上标记,最后floodfill内陆的水方块即
可得到若干个池塘,将池塘的面积和位置存进一个结构体中,并按照面积大小排序。再依次将这些池塘填上
土方块,直到剩下k个池塘。
note:
1:floodfill开始手残写错了,WA了一发才发现,注意写法。
date:
2016.10.4
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 60;
struct Node {
int r, c, val;
Node(int r_, int c_, int val_):r(r_),c(c_),val(val_) {}
Node(){}
bool operator < (const Node& rhs) const {
return val > rhs.val;
}
};
char G[maxn][maxn];
int n, m, k; //n行m列
bool vis[maxn][maxn];
int dirRow[] = {0, 0, 1, -1};
int dirCol[] = {1, -1, 0, 0};
bool isBoard(int row, int col) {
if(row == 0 || row == n-1 || col == 0 || col == m-1) return true;
else return false;
}
bool inside(int row, int col) {
return row >= 0 && row < n && col >= 0 && col < m;
}
int dfs(int row, int col) {
vis[row][col] = true;
int cnt = 0;
for(int d = 0; d < 4; d++) {
int nr = row + dirRow[d];
int nc = col + dirCol[d];
if(inside(nr, nc) && !vis[nr][nc] && G[nr][nc] == '.')
cnt += dfs(nr, nc);
}
return cnt + 1;
}
void update(int row, int col) {
G[row][col] = '*';
for(int d = 0; d < 4; d++) {
int nr = row + dirRow[d];
int nc = col + dirCol[d];
if(G[nr][nc] == '.' && inside(nr, nc)) update(nr, nc);
}
}
int main()
{
//freopen("in.txt", "r", stdin);
while(cin >> n >> m >> k) {
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++) cin >> G[i][j];
memset(vis, 0, sizeof(vis));
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++) if(isBoard(i, j) && !vis[i][j] && G[i][j] == '.') {
dfs(i, j);
}
/*
for(int i = 0; i < n; i++)
for(int j = 0; j < m; j++)
if(vis[i][j]) printf("@%d %d\n", i, j);
*/
int tmp;
priority_queue<Node> pq;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) if(!vis[i][j] && G[i][j] == '.') {
tmp = dfs(i, j);
//printf("#%d %d %d\n", i, j, tmp);
pq.push(Node(i, j, tmp));
}
}
int ans = 0, res = pq.size() - k;
while(res--) {
Node x = pq.top(); pq.pop();
ans += x.val;
update(x.r, x.c);
}
cout << ans << endl;
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++)
cout << G[i][j];
cout << endl;
}
}
return 0;
}
E
/*
translation:
contest id:723
给出一张无向图,没有重边和自回环,求在原图的基础上将其变成有向图使得进度和出度相同的节点最多。
并打印出来。
solution:
欧拉回路
可以很容易看出来所要求的节点数就是无向土中度数为偶数的点个数。但是确定每条边的方向就成了问题。因为
欧拉回路适用的情况是奇点个数小于等于2,所以不能直接用欧拉回路算法。所以建立一个虚拟节点。当有点的
度数为奇数时,就在虚拟节点和该点之间连接一条边是的该节点变成度数为偶数的节点。这样就可以使用欧拉回路
算法了。
note:
1:搞清楚欧拉回路的使用情况和条件。
2:在图论题中添加虚拟节点是个很常见的思维技巧。
date: 2016.10.5
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 200 + 5;
int G[maxn][maxn], n, m;
bool vis[maxn][maxn];
int d[maxn];
void euler(int u) {
for(int v = 0; v <= n; v++) if(G[u][v] && !vis[u][v]) {
vis[u][v] = vis[v][u] = 1;
euler(v);
if(u != 0 && v != 0) cout << u << " " << v << endl;
}
}
int main() {
//freopen("in.txt", "r", stdin);
int T;
cin >> T;
while(T--) {
cin >> n >> m;
memset(vis, 0, sizeof(vis));
memset(G, 0, sizeof(G));
memset(d, 0, sizeof(d));
int u, v;
for(int i = 0; i < m; i++) {
cin >> u >> v;
d[u]++; d[v]++;
G[u][v] = 1;
G[v][u] = 1;
}
int res = 0;
for(int i = 1; i <= n; i++) {
if(d[i] % 2 == 0) res++;
else {
G[i][0] = 1;
G[0][i] = 1;
}
}
cout << res << endl;
for(int i = 0; i <= n; i++) euler(i);
}
}
F
/*
contest id:723
translation:
给出一张无权图,求这张图的生成树,并且使得s,t两点的度数不超过ds,dt。
solution:
很容易想到就是用并查集,按照kruskal算法来写,但是由于加入了s,t两点的限制条件。所以不能简单加上限制条件
就直接套kruskal,会连第一个样例都过不了。因为本来有的边是不该选进来的,结果反而被添加。所以这个时候就
考虑贪心的思想。对于每条边设定一个度数上限,值为两端顶点的度数上限之和,对于s,t两点的上限即为ds,dt。对于
其它的点设定成INF。再添加一个度数值,两端顶点的度数之和。然后用并查集生成图的生成树的时候,先添加度数上限
比较大的边,在度数上限相同的情况下,优先添加度数值较少的边。如此即可得出生成树。
note:
date:
2016.9.5
*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200000 + 5;
struct Edge {
int from, to, dLimit, degree;
Edge(int f = 0, int t = 0, int l = 0, int d = 0):from(f), to(t), dLimit(l), degree(d) {}
bool operator < (const Edge& rhs) const {
if(dLimit == rhs.dLimit) return degree < rhs.degree;
else return dLimit > rhs.dLimit;
}
};
vector<Edge> edges;
vector<Edge> ans;
int par[maxn], d[maxn];
int high[maxn], degree[maxn];
int n, m, s, t, ds, dt;
void init(int n) {
edges.clear();
ans.clear();
for(int i = 0; i <= n; i++) {
par[i] = i;
high[i] = 0;
}
memset(d, 0, sizeof(d));
memset(degree, 0, sizeof(degree));
}
int getRoot(int x) {
if(par[x] == x) return x;
else return par[x] = getRoot(par[x]);
}
void unite(int x, int y) {
x = getRoot(x);
y = getRoot(y);
if(x == y) return;
if(high[x] < high[y]) par[x] = y;
else {
par[y] = x;
if(high[x] == high[y]) high[x]++;
}
}
bool same(int x, int y) {
return getRoot(x) == getRoot(y);
}
int main()
{
//freopen("in.txt", "r", stdin);
while(cin >> n >> m) {
int u, v; init(n);
for(int i = 0; i < m; i++) {
cin >> u >> v;
d[u]++; d[v]++;
edges.push_back(Edge(u, v));
}
cin >> s >> t >> ds >> dt;
int sz = edges.size(), d1, d2;
for(int i = 0; i < sz; i++) {
u = edges[i].from; v = edges[i].to;
if(u == s) d1 = ds;
else if(u == t) d1 = dt;
else d1 = maxn;
if(v == s) d2 = ds;
else if(v == t) d2 = dt;
else d2 = maxn;
edges[i].dLimit = d1 + d2;
edges[i].degree = d[u] + d[v];
}
sort(edges.begin(), edges.end());
int res = 0;
for(int i = 0; i < m; i++) {
u = edges[i].from; v = edges[i].to;
//printf("for edge %d->%d\n", u, v);
if(u == s && degree[s] >= ds) continue;
if(v == s && degree[s] >= ds) continue;
if(u == t && degree[t] >= dt) continue;
if(v == t && degree[t] >= dt) continue;
if(!same(u, v)) {
//printf("unite %d->%d\n", u, v);
unite(u, v);
degree[u]++; degree[v]++; res++;
ans.push_back(Edge(u, v));
}
if(res == n-1) break;
}
//cout << res << endl;
if(res != n-1) cout << "No" << endl;
else {
cout << "Yes" << endl;
for(int i = 0; i < ans.size(); i++)
cout << ans[i].from << " " << ans[i].to << endl;
}
}
return 0;
}