2018/5/24模拟赛总结

shzr带病AK虐爆全场...

T1n皇后:

这题没啥好说的...

T2有重复元素的排列问题:

【问题描述】
设R={ r1, r2 , …, rn}是要进行排列的n个元素。其中元素r1, r2 , …, rn可能相同。试设计一个算法,列出R的所有不同排列。
【编程任务】
给定n 以及待排列的n 个元素。计算出这n 个元素的所有不同排列。
【输入格式】
由perm.in输入数据。文件的第1 行是元素个数n,1≤n≤500。接下来的1 行是待排列的n个元素。
【输出格式】
计算出的n个元素的所有不同排列输出到文件perm.out中。文件最后1行中的数是排列总数。

出锅出在T2上,T掉了7个点...

考试时的想法是:生成r[1]~r[n]的全排列,之后用Hash+map去重(比只用map要快一(很)些(多))

然而还是T掉了..仔细一看数据范围\(n≤500\),全排列\(n!\)的复杂度能给到三十分就已经是仁慈了...

正解应该是用一个桶,记录每个字母的个数,然后枚举26个字母的全排列就好了..

正解代码如下:

#include<iostream>
#include<cstdio>
using namespace std;
int n,f[501],a[501],ans;
char r[501];
void search(int t) {
    int k;
    if(t>n) {
        ans++;
        for(k=1;k<=n;k++) printf("%c",a[k]+96);
        printf("\n");
        return;
    }
    for(k=1;k<=26;k++)
        if(f[k]>0) {
            a[t]=k; f[k]--;
            search(t+1);
            f[k]++;
        }
}
int main() {
    scanf("%d",&n);
    cin>>r;
    for(int i=0;i<n;i++) f[r[i]-96]++;
    search(1);
    printf("%d",ans);
    return 0;
}

但wzx同学发现了一种神奇做法:stl里的next_permutation

实测开\(O_2\) 8ms,不过正解200多ms是smg..,stl大法好!

代码如下:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define re register
using namespace std;

int n, tot;
char ch[500 + 1];

int main() {
    scanf("%d\n%s", &n, ch);
    sort(ch, ch + n);
    do {
        puts(ch);
        ++tot;
    }while(next_permutation(ch, ch + n));
    printf("%d", tot);
    return 0;
}

T3装载问题:

【问题描述】
有一批共n个集装箱要装上艘载重量为c的轮船,其中集装箱i的重量为wi。找出一种最优装载方案,将轮船尽可能装满,即在装载体积不受限制的情况下,将尽可能重的集装箱装上轮船。
【输入格式】
由文件load.in给出输入数据。第一行有2个正整数n和c。n是集装箱数,c是轮船的载重量。接下来的1行中有n个正整数,表示集装箱的重量。
【输出格式】
将计算出的最大装载重量输出到文件load.out。
【输入样例】
5 10
7 2 6 5 4
【输出样例】
10

一看,这明显是01背包啊!loli太毒瘤了..明明说是只考搜索的模拟赛,用搜索的这道题都T掉了...

可以把货物的重量看做价值(因为要求重量最大嘛..),然后跑一个sb背包就好.

闲得无聊打了一个暴力,被极限数据卡成狗...

T4字符序列(characts)

【问题描述】
从三个元素的集合[A,B,C]中选取元素生成一个N个字符组成的序列,使得没有两个相邻字的子序列(子序列长度=2)相同。例:N = 5时ABCBA是合格的,而序列ABCBC与ABABC是不合格的,因为其中子序列BC,AB是相同的。
对于由键盘输入的N(1<=N<=12),求出满足条件的N个字符的所有序列和其总数。

一开始以为长度不定,两个区间的位置没有限制,check函数写了一个三重循环的(把四重优化了一下)

然后发现不对啊!搜索里面这么check不超时才鬼了嘞

开始仔细读题:

  • 子序列长度=2

  • 两个相邻字的子序列

一下子check的复杂度就变成O(n)了...

打了打搜索发现\(n=12\)的数据好像要1s多才能跑出来..

算了,不剪枝了,打一个12的表就好了

loli出题的时候好像没有考虑到可打表的问题.

我的打表程序比正解还短233,毕竟只有12的大小..

T5图的m着色问题color

【问题描述】
给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G中每条边的2个顶点着不同颜色,则称这个图是m可着色的。图的m着色问题是对于给定图G和m种颜色,找出所有不同的着色法。
【编程任务】
对于给定的无向连通图G和m种不同的颜色,编程计算图的所有不同的着色法。
【输入格式】
文件color.in输入数据。第1行有3个正整数n,k 和m,表示给定的图G有n个顶点和k条边,m种颜色。顶点编号为1,2,…,n。接下来的k行中,每行有2个正整数u,v,表示图G 的一条边(u,v)。
【输出格式】
程序运行结束时,将计算出的不同的着色方案数输出到文件color.out中。

当时用邻接表(又是一道图论题,毒瘤啊)没有打出来..就用的邻接矩阵,生成颜色的全排列再\(n^2\)遍历一遍判断

T了三个点(三个点卡卡时就过了..满地打滚求O3优化...)

考完以后用邻接表打了一遍,代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define re register
using namespace std;

const int MAXN = 100 + 5;
const int MAXM = MAXN * (MAXN - 1) / 2;

int n, k, m;
int tot, c[MAXN];
bool vis[MAXN];

int edge_num, head[MAXN];
struct Edge {
	int to, nxt;
}h[MAXM << 1];

inline int read() {
    int x=0; char ch = getchar();
    while(ch<'0' || ch>'9') ch = getchar();
    while(ch>='0' && ch<='9')
      x=(x<<3)+(x<<1)+ch-48, ch=getchar();
    return x;
}

inline void Add(int from, int to) {
	h[++edge_num].nxt = head[from];
	h[edge_num].to = to;
	head[from] = edge_num;
}

void dfs(int u) {
    if(u == n) {
        ++tot;
        return;
    }
    for(re int i=1; i<=m; ++i) {
    	bool fl = 1;
    	for(re int j=head[u+1]; j; j=h[j].nxt)
    		if(c[h[j].to] == i) {
    			fl = 0;
    			break;
			}
		if(!fl) continue;
		c[u + 1] = i;
		dfs(u + 1);
		c[u + 1] = 0;
	}
}

int main() {
    n = read(), k = read(), m = read();
    for(re int i=1; i<=k; ++i) {
        int x = read(), y = read();
        Add(x, y), Add(y, x);
    }
    dfs(0);
    printf("%d\n", tot);
    return 0;
}

这次模拟赛其实好多人都能AK的,但只有一个人AK...

大家都交卷交的太早了...

posted @ 2018-05-25 09:06  DEVILK  阅读(582)  评论(1编辑  收藏  举报