您的位置:首页 > 其它

某模拟题题解

2016-08-29 17:29 162 查看
描述(A 输入文件 : A.input 输出文件 : A.output)
一个城市的构成是一颗n 个节点的树(2 ≤ n ≤ 200), 现在需要在树中找出两条不相交的路
径(即两条路径不能有重边也不能有重点),使得路径的长度的乘积最大。
输入描述
第一行一个数n 表示这个城市一共有 n 个节点。
接下来 n-1 行,每行两个数ai 和bi (1 ≤ ai,bi ≤ n ),分别表示从ai 到bi,有一条边,每条边
的长度为1。
输出描述
输出一行一个数表示两条路径长度最大的乘积。
样例数据
样例输入1:
7
1 2
1 3
1 4
1 5
1 6
1 7
样例输出1:
0
样例输入2:
6
1 2
2 3
2 4
5 4
6 4
样例输出2:
4

  第一题没多大技术含量,枚举每一条边,把这棵树分成两棵子树,再在这两棵子树上求最大的路径,这里用两种

方法,第一种是树规,第二种是两次dfs,第一种这里就不讲了,就说第二种,首先从一个点开始深搜,找到一个离当

前点最远的一个点,再从这个点开始,找到一个离这个点最远的点,这两个点的距离是最远的。

  然后两部分都执行以下这个,找出这个距离,相乘,不断更新结果就行了

Code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<vector>
using namespace std;
typedef bool boolean;
template<typename T>
inline void readInteger(T& u){
char x;
while(!isdigit((x = getchar())));
for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
ungetc(x, stdin);
}
typedef class Edge{
public:
int end;
int next;
Edge(const int end = 0, const int next = 0):end(end),next(next){}
}Edge;
int ce;
int *h;
Edge* edge;
inline void addEdge(int from, int end){
edge[++ce] = Edge(end, h[from]);
h[from] = ce;
}
int n;
int maxd;
int noded;
void dsearch(int node, int split, int depth, int last){
for(int i = h[node]; i != 0; i = edge[i].next){
if(i == split || i == split + 1 || edge[i].end == last)    continue;
dsearch(edge[i].end, split, depth + 1, node);
}
if(maxd <= depth){
maxd = depth;
noded = node;
}
}
int farSearch(int node, int split){
dsearch(node, split, 0, 0);
int buf = noded;
maxd = 0;
dsearch(buf, split, 0, 0);
return maxd;
}
inline void init(){
readInteger(n);
edge = new Edge[(const int)(2 * n + 1)];
h = new int[(const int)(n + 1)];
memset(h, 0, sizeof(int) * (n + 1));
for(int i = 1, a, b; i < n; i++){
readInteger(a);
readInteger(b);
addEdge(a, b);
addEdge(b, a);
}
}
inline void solve(){
long long result = 0;
long long a, b;
for(int i = 1; i <= n; i++){
for(int j = h[i]; j != 0; j = edge[j].next){
if((j & 1) == 0)    continue;
a = farSearch(i, j);
maxd = 0;
b = farSearch(edge[j].end, j);
maxd = 0;
result = max(result, a * b);
}
}
cout<<result;
}
int main(){
freopen("A.input", "r", stdin);
freopen("A.output", "w", stdout);
init();
solve();
return 0;
}


描述(B 输入文件 : B.input 输出文件 : B.output)
有n 个人需要看医生, 其中第i 个人需要看医生的次数是ai, 一开始从1 到n 依次排列组成
一个等待队伍, 每个人依次看医生, 那么每个人看完医生有两种情况, 第一种情况:他
已经看够他需要看医生的次数,那么他会离开。第二种情况:他还需要看医生,那么他就
会选择重新站在队伍的最后。选择医生想知道,当他看过k 次病人之后,这个等待队伍是
什么样。
输入描述
第一行两个正整数 n 和 k (1 ≤ n ≤ 105, 0 ≤ k ≤ 1014)
第二行一共个n 正整数 a1, a2, ..., an (1 ≤ ai ≤ 109),用空格隔开。
输出描述
一行,按队列的顺序输出需要的结果,每两个数之间用空格隔开,注意不要输出多余的空
格。数据保证此时队列里至少有一个人。
样例数据
样例输入1:
3 3
1 2 1
样例输出1:
2
样例输入2:
7 10
1 3 3 1 2 3 1
样例输出2:
6 2 3

  这道含金量不大,主要是这坑人的数据范围。。。O(k)的算法都会TLE,怎么办?不断把k减小,

首先从小到大排个序,然后看k次后排序后的第i个人有没有看完,看完了就把所有人已经看了的次数加上

这个数(不直接去更新,否则速度会变慢很多),一直到最后剩下次数不能使一个人离开队列

  接着剩下的人每个人至少还可以看k / remain次,所以每个人至少看的次数还要加上这么多

最后就直接模拟,输出。

Code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<vector>
using namespace std;
typedef bool boolean;
template<typename T>
inline void readInteger(T& u){
char x;
while(!isdigit((x = getchar())));
for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
ungetc(x, stdin);
}
typedef class sdata{
public:
int _count;
int times;
sdata(int times = 0, int _count = 0):times(times), _count(_count){}
}sdata;
int n;
long long k;
int* a;
int* b;
vector<sdata> qs;
inline void init(){
readInteger(n);
readInteger(k);
a = new int[(const int)(n + 1)];
b = new int[(const int)(n + 1)];
for(int i = 1; i <= n; i++)
readInteger(a[i]);
memcpy(b, a, sizeof(int) * (n + 1));
}
inline void solve(){
sort(b + 1, b + n + 1);
int _count = 0;
for(int i = 1; i <= n; i++){
if(i != 1 && b[i] != b[i - 1]){
qs.push_back(sdata(b[i - 1], _count));
_count = 0;
}
_count++;
}
qs.push_back(sdata(b
, _count));

int remain = n;        //剩下的数量
int subed = 0;        //已经减去的值,直接修改会浪费时间
for(int t = 0; (remain * 1LL * (qs[t].times - subed)) <= k && remain > 0; t++){
k -= remain * 1LL * (qs[t].times - subed);
remain -= qs[t]._count;
subed += qs[t].times - subed;
}

if(remain == 0)    return;
subed += k / remain;
k %= remain;

for(int i = 1; i <= n; i++)    a[i] -= subed;
int i;
for(i = 1; i <= n && k; i++){
if(a[i] <= 0)    continue;
a[i]--;
k--;
}

for(int j = i; j <= n; j++)
if(a[j] > 0)    printf("%d ", j);
for(int j = 1; j < i; j++)
if(a[j] > 0)    printf("%d ", j);
}
int main(){
freopen("B.input", "r", stdin);
freopen("B.output", "w", stdout);
init();
solve();
return 0;
}


描述(C 输入文件 : C.input 输出文件 : C.output)
有n 个任务需要你去完成,这些任务分布在3 个不同的房间,编号为1,2,3, 其中有些任务
必须在一些其他的任务完成之后才能完成。现在知道完成一个任务需要1 的时间,现在知
从房间1 到2,2 到3,3 到1 需要1 的时间,从1 到3,2 到1,3 到2 需要2 的时间。现
在你可以选择你一开始的房间,问完全所有任务的最短时间是多少,保证可以完成。
输入描述
第一行一个数 n (1 ≤ n ≤ 200) 。
第二行 n 个数, 第i 个数 ci (1 ≤ ci ≤ 3) 表示该任务所在的房间。.
接下来一共 n 行. 第 i 行的第一个数是 ki (0 ≤ ki ≤ n - 1),表示完成第i 个任务之前需要完
成的任务个数,之后 ki 个正整数表示需要提前完成的任务的编号。
输出描述
输出一个正整数表示完成任务需要是时间。
样例数据
样例输入1:
5
2 2 1 1 3
1 5
2 5 1
2 5 4
1 5
0
样例输出1:
7

  首先可以发现从1走到3,还不如从1走到2再走到3,虽然在路上花费的时间是一样的,但是可能可以处理

更多的任务。像样思考,从某个房间开始到最后一个任务处理完毕的方案是唯一的,唯一影响结果的就是开始

的房间,所以枚举开始的房间然后拓扑排序就行了。

Code

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<queue>
#include<vector>
using namespace std;
typedef bool boolean;
template<typename T>
inline void readInteger(T& u){
char x;
while(!isdigit((x = getchar())));
for(u = x - '0'; isdigit((x = getchar())); u = (u << 3) + (u << 1) + x - '0');
ungetc(x, stdin);
}
typedef class Edge{
public:
int end;
int next;
Edge(const int end = 0, const int next = 0):end(end),next(next){}
}Edge;
int ce;
int *h;
Edge* edge;
int* in;
inline void addEdge(int from, int end){
edge[++ce] = Edge(end, h[from]);
h[from] = ce;
in[end]++;
}
int n;
int* room;
inline void init(){
readInteger(n);
room = new int[(const int)(n + 1)];
edge = new Edge[(const int)(n * n / 2 + 1)];
h = new int[(const int)(n + 1)];
in = new int[(const int)(n + 1)];
memset(h, 0, sizeof(int) * (n + 1));
memset(in, 0, sizeof(int) * (n + 1));
for(int i = 1; i <= n; i++)
readInteger(room[i]);
for(int i = 1, k, a; i <= n; i++){
readInteger(k);
while(k--){
readInteger(a);
addEdge(a, i);
}
}
}
int* deg;
queue<int> que[3];
inline int tp_sort(int s){
deg = new int[(const int)(n + 1)];
memcpy(deg, in, sizeof(int) * (n + 1));
int _count = 0;
for(int i = 1; i <= n; i++)
if(deg[i] == 0){
_count++;
que[room[i] - 1].push(i);
}
int status = s;
int result = 0;
while(_count){
while(!que[status].empty()){                //处理完所有可以做的任务
int u = que[status].front();
que[status].pop();
for(int i = h[u]; i != 0; i = edge[i].next){
deg[edge[i].end]--;
if(deg[edge[i].end] == 0){
que[room[edge[i].end] - 1].push(edge[i].end);
_count++;
}
}
_count--;
}
if(_count == 0)    break;
result++;
status++;
if(status > 2)    status = 0;
}
delete[] deg;
return result + n;
}
int main(){
freopen("C.input", "r", stdin);
freopen("C.output", "w", stdout);
init();
int result = 0xfffffff;
for(int i = 0; i < 3; i++)    result = min(result, tp_sort(i));
printf("%d", result);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: