算法竞赛入门竞赛 入门经典 第七章 个人记录

不会暴力的,连暴力都不会的,一点暴力都不会的……

7-1 除法

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

struct node
{
	int fghij;
	int a[10];
};

vectorv;
void init()
{
	int a[10];
	for (int i = 1234; i < 100000; i++)
	{
		memset(a, 0, sizeof(a));
		if (i < 10000)a[0] = 1;
		int n = i;
		int flag = 1;
		while (n)
		{
			int t = n % 10;
			n /= 10;
			if (a[t]) { flag = 0; break; }
			else a[t] = 1;
		}
		if (!flag)
			continue;
		else
		{
			node p;
			p.fghij = i;
			memcpy(p.a, a,sizeof(a));
			v.push_back(p);
		}
	}
}

int main()
{
	int n;
	init();
	int first = 1;
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);
	while (cin >> n && n)
{
		if (first)
			first--;
		else
			cout << endl;
		vectora, b;
		for (int i = 0; i < v.size(); i++)
		{
			int ttt = v[i].fghij * n;
			node ls;
			ls.fghij = ttt;
			memcpy(ls.a, v[i].a, sizeof(ls.a));
			int t = ttt;
			int flag = 1;
			if (t < 10000)
			{
				int tt = 0;
				if (ls.a[tt]) { continue; }
				else ls.a[tt] = 1;
			}
			while (t)
			{
				int tt = t % 10;
				t /= 10;
				if (ls.a[tt]) { flag = 0; break; }
				else ls.a[tt] = 1;
			}
			if (!flag)
				continue;
			else
			{
				a.push_back(ttt);
				b.push_back(v[i].fghij);
				//printf("%05d / %05d = %d\n", ttt, v[i].fghij, n);
			}
		}
		if (a.size())
		{
			for (int i = 0; i < a.size(); i++)
			{
				printf("%05d / %05d = %d\n", a[i], b[i], n);
			}
		}
		else
		{
			printf("There are no solutions for %d.\n", n);
		}
	}
	//fclose(stdin);
	//fclose(stdout);
	//system("pause");
	return 0;
}

本来也是很简单的一个东西,硬是被我弄成了这个样子,然后因为提前打表的关系,所以判断重复还得再开一个数组,可能直接一个二维数组会更好(会吗?)

这个我写的这个其实有点多余的,有些东西还可以包装成函数,实在懒得弄了,所以看起来也很繁琐。

然后紫书的代码仓库的代码是用sprintf把被除数和除数变成一个字符串然后遍历字符串判断是否有重复。

7-2 最大乘积

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);
	int n;
	int cas = 1;
	while (cin >> n)
	{
		long long maxx = 0;
		int a[30];
		for (int i = 0; i < n; i++)
		{
			cin >> a[i];
		}
		for (int kt = 0; kt < n; kt++)
		{
			long long t = 1;
			for (int j = kt; j < n; j++)
			{
				t *= a[j];
				if (t > maxx)maxx = t;
			}
		}

		printf("Case #%d: The maximum product is %lld.\n\n", cas++, maxx);
	}
	//fclose(stdin);
	//fclose(stdout);
	//system("pause");
	return 0;
}

暴力子序列,容易漏掉只有一个数字,还有输出末尾的‘.’,以及输出的是一个空行。

 

7-3 分数拆分

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int gcd(int a, int b)
{
	while (a%b)
	{
		int t = a % b;
		a = b;
		b = t;
	}
	return b;
}

int judge(int k, int y)
{
	int fm, fz;
	int bs = k*y/gcd(k, y);
	int kfz, yfz;
	kfz = bs/k;
	yfz = bs/y;
	fz = kfz - yfz;
	fm = bs;
	if (fz == 0)
		return -1;
	else if (fz == 1)
		return bs;
	bs = gcd(fz, fm);
	fz /= bs;
	fm /= bs;
	if (fz == 1)
		return fm;
	else
		return -1;
}

int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);
	int k;
	while (cin >> k)
	{
		int x, y;
		vectorvx, vy;
		for (y = k; y <= 2 * k; y++)
		{
			x = judge(k, y);
			if (x != -1)
			{
				vx.push_back(x);
				vy.push_back(y);
			}
		}
		cout << vx.size() << endl;
		for (int i = 0; i < vx.size(); i++)
		{
			printf("1/%d = 1/%d + 1/%d\n", k, vx[i], vy[i]);
		}
	}
	//fclose(stdin);
	//fclose(stdout);
	//system("pause");
	return 0;
}

单纯的模拟分数减法……值得一提的是分子都得是1,还有整除可能会等于1什么的,反正不是很难注意点细节就可以了。其他的紫书上很详细了,y从k枚举到2k就可以了,这个是难点紫书就讲了然后就没有了。

 

7.2是枚举全排列的一些方法和原理 代码实现也有 姑且贴一个有重复全排列的。

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

int A[100],P[100];
void permutation(int n,int *P, int* A,int cur)
{
	if (cur == n)
	{
		for (int i = 0; i < n; i++)cout << A[i] << " ";
		cout << endl;
	}
	else
	{
		for (int i = 0; i < n; i++)
		{
			if (!i || P[i] != P[i - 1])
			{
				int c1 = 0, c2 = 0;
				for (int j = 0; j < cur; j++)
				{
					if (A[j] == P[i])c1++;
				}
				for (int j = 0; j < n; j++)
				{
					if (P[j] == P[i])c2++;
				}
				if (c1> n)
	{
		for (int i = 0; i < n; i++)
			cin >> P[i];
		sort(P, P + n);
		permutation(n, P, A, 0);
	}
	//fclose(stdin);
	//fclose(stdout);
	system("pause");
	return 0;
}

递归虐我千百遍系列……

7.3.1

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
 
int a[105];
void print_subset(int n, int *a, int cur)
{
	for (int i = 0; i < cur; i++)printf("%d ", a[i]);
	if(cur)printf("\n");
	int s = cur ? a[cur - 1] + 1 : 1;
	for (int i = s; i <= n; i++)
	{
		a[cur] = i;
		print_subset(n, a, cur + 1);
	}
}

int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);
	int n;
	while (cin >> n)
	{
		//for (int i = 0; i < n; i++)
		//	cin >> a[i];
		print_subset(n, a, 0);
	}
	//fclose(stdin);
	//fclose(stdout);
	//system("pause");
	return 0;
}

大家好现在是11.6 15:55 我要开始看书了 八皇后我觉得看不到了 之前的几个小时仿佛什么也没干尽在摸鱼了我的天哪。

大致的感觉就是先输出a这个数组现有的,然后看看要不要再加点,加的进去,那么再递归进去。如果加不进去,那么结束本次递归,回到可以继续递归的地方或者结束递归。

啊对了 出于个人原因把范围0~n-1改成了1~n 所以和书上的源代码有一丢丢的不同(其实一样)。

7.3.2

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
 
int b[105];
void print_subset(int n, int b[], int cur)
{
	if (cur == n+1)
	{
		int flag = 0;
		for (int i = 1; i <= cur; i++)
		{
			if (b[i])
			{
				flag = 1;
				cout << i << " ";
			}
		}
		if(flag)
			cout << endl;
		return;
	}
	b[cur] = 1;
	print_subset(n, b, cur + 1);
	b[cur] = 0;
	print_subset(n, b, cur + 1);
}

int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);
	int n;
	while (cin >> n)
	{
		//for (int i = 0; i < n; i++)
		//	cin >> a[i];
		print_subset(n, b, 1);
	}
	//fclose(stdin);
	//fclose(stdout);
	//system("pause");
	return 0;
}

联想到了哈希排序,也都挺有趣的,这次把0~n-1改动成1~n稍稍难为了一点,不知道还有没有更好的方法,我尽力了,算法的优良不考虑的话讲真我会选择这个,我觉得以后我再写写出来的应该也是这个,所以前面那个我更应该好好看看……更一般一点我觉得……

 

7.3.3 二进制

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
 
int b[105];
void print_subset(int n,int s)
{
	for (int i = 0; i <= n; i++)
	{
		if (s & (1 << i))
		{
			printf("%d ", i);
		}
	}
	printf("\n");
}
 
int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);
	int n;
	while (cin >> n)
	{
	/*	int a[105];
		for (int i = 0; i < n; i++)
			cin >> b[i];*/
		for(int i=0;i<(1<

大失败……暂时先不管了 我应该会找个时间仔细的研究二进制的这些符号的。。。

 

7.4.1 八皇后问题

#include
#include
using namespace std;

int C[50], vis[3][50], tot = 0, n = 8, nc = 0;

void search(int cur) {
  int i, j;
  nc++;
  if(cur == n) {
    tot++;
  } else for(i = 0; i < n; i++) {
    if(!vis[0][i] && !vis[1][cur+i] && !vis[2][cur-i+n]) {//cur是行 i是列
      C[cur] = i;
      vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 1;
      search(cur+1);
      vis[0][i] = vis[1][cur+i] = vis[2][cur-i+n] = 0;
    }
  }
}

int main() {
  scanf("%d", &n);
  memset(vis, 0, sizeof(vis));
  search(0);
  printf("%d\n", tot);
  printf("%d\n", nc);
  return 0;
}

0数组是保证同一列只有一个,1数组cur-i是主对角线,因为其可能是负数,所以加上n(甚至我觉得加上一个比n大的数都可以),2数组的i+cur是保证副对角线只有一个皇后。

 

hdu 2553 N皇后问题

#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
 
int n;
int vis[3][50];
int C[100];

int id;
void search(int cur)
{
	if (n == cur)
	{
		id++;
	}
	else
	{
		for (int i = 0; i < n; i++)
		{
			if (!vis[0][i] && !vis[1][cur + i] && !vis[2][cur - i + n])
			{
				vis[0][i] = vis[1][cur + i] = vis[2][cur - i + n] = 1;
				search(cur+1);
				vis[0][i] = vis[1][cur + i] = vis[2][cur - i + n] = 0;
			}
		}
	}
}
 
int main()
{
	//freopen("D:\\in.txt", "r", stdin);
	//freopen("D:\\out.txt", "w", stdout);
	int a[15];
	for(n=1;n<=10;n++)
	{
		id = 0;
		memset(vis, 0, sizeof(vis));
		search(0);
		a[n] = id;
		//cout<< id << endl;a
	}
	int t;
	while (cin >> t && t)
	{
		cout << a[t] << endl;
	}
	//fclose(stdin);
	//fclose(stdout);
	//system("pause");
	return 0;
}

这道题他居然得提前打表,不提前打表他就是过不了,就很气有没有……大体思路还是原来的那些。

 

OpenJ_Bailian - 2754 八皇后

#include 
#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 300005;

struct node
{
	long long xi, yi;
};

int n;
int vis[3][60];
int c[15];
int tot;
vectorv;
void search(int cur)
{
	if (cur == n+1)
	{
		tot++;
		int sum = 0;
		for (int i = 0; i <= 8; i++)
		{
			sum *= 10;
			sum += c[i];
		}
		v.push_back(sum);
		//system("pause");
	}
	else
	{
		for (int i = 1; i <= n; i++)
		{
			if (!vis[0][i] && !vis[1][i + cur] && !vis[2][i - cur + n])
			{
				vis[0][i] = vis[1][i + cur] = vis[2][i - cur + n] = 1;
				c[cur] = i;
				search(cur + 1);
				vis[0][i] = vis[1][i + cur] = vis[2][i - cur + n] = 0;
			}
		}
	}
}
int main()
{
	n = 8;
	int t;
	tot = 0;
	memset(vis, 0, sizeof(vis));
	search(1);
	sort(v.begin(), v.end());
	scanf("%d", &t);
	while(t--)
	{
		int tt;
		scanf("%d", &tt);
		cout << v[tt-1] << endl;
	}
	//system("pause");
	return 0;
}

这题应该求的是每次的序号,那么我的想法就是保存每个序列然后排序一下就好了。就很粗暴,爽到。

 

OpenJ_Bailian - 2698 八皇后问题

#include 
#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 300005;

struct node
{
	long long xi, yi;
};

int n;
int vis[3][60];
int m[15][15];
int tot;
void search(int cur)
{
	if (cur == n)
	{
		tot++;
		printf("No. %d\n", tot);
		for (int i = 0; i < 8; i++)
		{
			for (int j = 0; j < 8; j++)
			{
				printf("%d ", m[i][j]);
			}
			printf("\n");
		}
		//system("pause");
	}
	else
	{
		for (int i = 0; i < n; i++)
		{
			if (!vis[0][i] && !vis[1][i + cur] && !vis[2][i - cur + n])
			{
				vis[0][i] = vis[1][i + cur] = vis[2][i - cur + n] = 1;
				m[i][cur] = 1;
				search(cur + 1);
				vis[0][i] = vis[1][i + cur] = vis[2][i - cur + n] = 0;
				m[i][cur] = 0;
			}
		}
	}
}
int main()
{
	//while (scanf("%d", &n) != EOF)
	{
		n = 8;
		tot = 0;
		memset(vis, 0, sizeof(vis));
		search(0);
	}
	return 0;
}

本来打算用vector存储x和y,但是我失败了,后来想到可以直接二维数组保存。然后问题又来了,因为书上的代码cur表示行,i表示列所以会和题目要求的顺序不一样,然后仔细观察(我是偶然发现),题目的生成cur是列,所以是按列来的,那么接下来i就是行,那么又和原来的一样了,非常简单粗暴了。

 

7.4.2

uva 524 素数环

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

int a[50];
int is[200] = {0};
int pri[100];

void init()
{
	int cnt = 0;
	for (int i = 2; i < 200;i++)
	{
		if (!is[i])pri[cnt++] = i;
		for (int j = 0; i*pri[j] < 200 && j < cnt; j++)
		{
			is[i*pri[j]] = 1;
			if (i % pri[j] == 0)break;
		}
	}
}

int vis[100];
int n;
void solve(int cur)
{
	if (cur == n && is[a[0] + a[n-1]] == 0)
	{
		for (int i = 0; i < n; i++)
		{
			printf("%d", a[i]);
			printf(i == n-1 ? "\n" : " ");
		}
	}
	else
	{
		for (int i = 1; i <= n; i++)
		{
			{
				if (vis[i]==0 && is[a[cur-1] + i] == 0)
				{
					a[cur] = i;
					vis[i] = 1;
					solve(cur + 1);
					vis[i] = 0;
				}
			}
		}
	}
}

int main()
{
	int cas = 0;
	init();
	int first = 0;
	while (cin >> n)
	{
		if (first)cout << endl;
		else first = 1;
		cout << "Case " << ++cas << ":" << endl;
		a[0] = 1;
		vis[1] = 1;
		solve(1);
	}
	system("pause");
}

这道题似曾相识啊,前边几篇还有我写的博客呢。而且我居然写出了不仅仅以1开头的环(当然没有什么卵用)。

今天大部分时间在摸鱼,任务没有完成,难过。

 

11.6 看完了7.1 7.2 在晚上决定水题并稍微休息吸收。

11.7 下午没有课 应该可以把7.3看完 7.4的回溯法应该可以看掉八皇后 其他的暂时不做打算

接着周四两道周五两道我觉得这个星期应该可以看掉7.4。

这个星期的计划先这样!

你可能感兴趣的:(UVA)