#include
#include
#include
#include
#include
using namespace std;
const int N = 15;
int arr[N],rs[2*N],ls[2*N],used[N];
int n,res=0;
//bool check(int i, int j) {//尝试在arr[i]放j,即在i,j处放位置
// for (int k = 1; k < i; k++) {
// if (arr[k] == j) {//第j列用过了,再用就会一列有两个数
// return false;
// }
// if ((k - arr[k] == i - j) || (k + arr[k] == i + j)) {
// return false;
// }
// }
// return true;
//}//由于是行数组,所以不用担心一行有两个,即一行(一个数组格子)放不下两个数,只能放一个数
//每次都检查,会T掉
void dfs(int i) {
if (i == n + 1) {
if (res < 3) {
for (int j = 1; j <= n; j++) {
cout << arr[j] << " ";
}
cout << endl;
}
res++;
return;
}
for (int j = 1; j <= n; j++) {
if (used[j] || rs[i + j] || ls[i - j + n]) {
continue;
}
used[j] = 1, rs[i + j] = 1, ls[i - j + n] = 1;
arr[i] = j;
dfs(i + 1);
used[j] = 0, rs[i + j] = 0, ls[i - j + n] = 0;
}
}
int main() {
cin >> n;
dfs(1);
cout << res;
return 0;
}
输入的第一行为一个单独的整数 �n 表示单词数,以下 �n 行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。
输出格式
只需输出以此字母开头的最长的“龙”的长度。
输入输出样例
5 at touch cheat choose tact a
23
用vector string数组接收输入
用哈希表记录每个单词的出现次数
?怎么拼接?
?怎么检查单词最后一位?
由龙头往后接,不断更新尾巴,然后从单词数组头往后扫,直到都用过了,或没有了,就和已有答案比较一下并更新
int use[20], length = 0, n;
string str[20];
int canlink(string str1, string str2) {//不断返回两个单词的最短拼接长度,其实可以用一个二维数组来保存
//以减少调用次数
for (int i = 1; i < min(str1.length(), str2.length()); i++) {//重叠长度从1开始增加
int flag = 1;
for (int j = 0; j < i; j++) {//j是对接的位数
if (str1[str1.length() - i + j] != str2[j]) {//第一个字符串从尾部,第二个从头部
flag = 0;
}
}
if (flag)return i;
}
return 0;
}
void solve(string strnow, int lengthnow) {
length = max(lengthnow, length);
for (int i = 0; i < n; i++) {//从头开始扫单词数组
if (use[i] >= 2) { continue; }//如果这个单词用过两次就跳过
int c = canlink(strnow, str[i]);//得到与上个单词的最短拼接长度
if (c > 0) {//只有拼接得上才递归向下继续拼接
use[i]++;//拼接后,最后的单词依然是这个拼接的单词,即只看最后的部分,不管整体,只是更新整体的长度
solve(str[i], lengthnow + str[i].length() - c);//拼接上了第i个单词,那么末尾就是第i个单词和其他单词拼
use[i]--;
}
}
}
cin >> n;
for (int i = 0; i <= n; i++) {
cin >> str[i];
}
solve(' ' + str[n], 1);
cout << length;
如touchc,chceat,重叠部分c,ch,chc,要让最长,就要重叠部分最小,拼接起来就应该是touchchceat,而不应该继续重叠,所以就要让拼接长度从小到大,即如果一旦拼接得上,就立即终止继续增长拼接长度,这样就能保证拼接长度是最短的
而如果要让拼接长度最大,就需要让拼接长度从大到小遍历,即如果一旦拼接得上,就立即终止继续缩短拼接长度
//yc[i][j]来存储第i个单词后连接第j个单词的最小重叠部分(mt函数)
//预处理
//预处理完后是深搜dfs
//
//
string tr[30][30];
int mt(int x, int y) {//返回x单词后连接一个y单词的最小重叠部分
//x单词从后往前,y单词从前往后
for (int k = tr[x].size() - 1; k >= 0; k--) {//从x单词尾部向前看看最小重叠部分是从哪开始
for (int kx = k; kx < tr[x].size(); kx++) {//检测k到末尾
if (tr[x][kx] != tr[y][ky++]) {
pp = false;//不匹配
break;
}
}
if(pp=true){//都相等,匹配,直接返回
return tr[x].size() - k;
}
ky = 0;
pp = true;
}
return 0;
}
void dfs(int p) {
bool jx = false;
for (int j = 1; j <= n; j++) {
if (vis[j] >= 2)continue;
if (yc[p][j] == 0)continue;//不能拼上
if (yc[p][j] == tr[p].size() || yc[p][j] == tr[j].size())continue;//存在包含关系
an += tr[j].size() - yc[p][j];
vis[j]++;
jx = true;
dfs(j);
an -= tr[j].size() - yc[p][j];
vis[j]--;
}
if (jx == false) {
ans = max(ans, an);
}
return;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
yc[i][j] = mt(i, j);//预处理
}
}
for (int i = 1; i <= n; i++) {
if (tr[i][0] == ch) {//从头到尾看一下有没有指定的字母开头
vis[i]++;
an = tr[i].size();
dfs(i);//以这个字母为开头,覆盖掉了指定的字符
vis[i] = 0;
}
}
并且,这一行中从第 3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和。
就是说从第三个开始,至少大于斐波那契的增长,而斐波那契40项左右就过2^30了,所以实际可用范围在50之内
//
/*
dfs(long long cur) {//cur表当前重量
if (cur + b[index] <= maxc) {//b为前缀和,如果当前重量加上Index前面所有砝码都不过max,就return
return;
}
maxc = max(cur, maxc);
}*/
long long sum[50], a[50];
int c, n;
long long ans = 0;
void dfs(int cur, long long x)
{
if (x > c)return;
if (sum[cur - 1] + x <= c)
//一个剪枝:如果前面那些砝码可以全部取走,那直接取走即可。
{
ans = max(ans, sum[cur - 1] + x);
return;
}
ans = max(ans, x);
for (int i = 1; i < cur; i++)
dfs(i, x + a[i]);
return;
}
cin >> n >> c;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
dfs(n + 1, 0);
cout << ans << endl;
max()函数中必须是同类型,即都为Longlong,不能一个Int,一个Longlong
背包的思路可以用,但是不能用背包的解法,因为最大到了2^30,数组装不下
1.倒数两位,四位,整个都构成质数
2/检测日期是否真实存在(闰年,月份,头疼)
#include
#include
#include
#include
#include
using namespace std;
const int p[] = { 0,3,5,7,11,13,17,19,23,29,31 };//这是每个月里的质数日,提前做出检验
//一定要注意这个数组最后一位要放一个比d数组大的数,目的是终止循环,如果让31作为最后一个数字,那么在到31时,还要继续往后走,但后面已经没有数了
//所以需要一个大于任何d数组中的数作为结尾,来终止对p数组的访问
//或者在循环终止条件中写入j<=这个数组长度
const int d[] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int T, a[66], t, ans[66666], tot;
char s[10];
inline bool is_prime(int x) {
for (int i = 2; i * i <= x; i++) {
if (x % i == 0) {
return false;
}
}
return true;
}
int main() {
ios::sync_with_stdio(0);
for (int i = 1; i <= 12; i++) {//i表示月份,开始组合月日
for (int j = 1; p[j] <= d[i]&&j<=10; j++) {//要保证每个月里的质数日不超过当月的限制,然后遍历j
if (is_prime(i * 100 + p[j])) {
a[++t] = i * 100 + p[j];//之所以是前置++,是让t还能起到计数的作用,还能填数
//即t初始为0,先是t++,t=1,(相当于有数了,然后cnt++),再在一号位置上填数
}
}
}
for (int i = 4; i <= 9999; i += 4) {//四年一闰
if ((i % 100 || !(i % 400)) && is_prime(i * 10000 + 229)) {//i%100表示如果能除尽,即为0,不闰,不判断
//不然就不为0,做出判断,即组合起来的时间得是质数
ans[++tot] = i * 10000 + 229;
}
}//特判闰年,四年一闰,百年不闰,400年又闰
//闰年特殊就特殊在二月多一天,所以考虑闰年主要就是考虑这多出来的一天229
for (int i = 1; i <= 9999; i++) {
for (int j = 1; j <= t; j++) {//j是已经组合好的质数日月,再和年组合,判断是不是质数
if (is_prime(i * 10000 + a[j])) {
ans[++tot] = i * 10000 + a[j];
}
}
}
//至此得到所有的质数时间
cin >> T;
while (T--) {
cin >> (s + 1);
int cnt = 0;
for (int i = 1; i <= tot; i++) {//从所有的质数时间中开始检验
int now = ans[i], flag = 1;
for (int j = 8; flag && j; j--, now /= 10) {//循环条件为flag保持与尚有存为
if (s[j] != '-' && s[j] - '0' != now % 10) {//now%10得到当前的最后一位数
//可以匹配上的条件为当前位是-,即未知
//或者当前位和当前的质数时间的对应位置数字相同
//只有满足匹配条件才可继续匹配,直到匹配完成是可能的
//或者不匹配,匹配不上,试试下一个质数时间
flag = 0;
}
}
cnt += flag;//加上检测过的flag
}
cout << cnt << endl;
}
return 0;
}
1.怎么判断停止扩散
A:碰壁或者超过已扩散油滴所允许的最大半径
2.油滴滴后怎么对其他油滴造成影响?怎么写?
A:通过数组标记已扩展的油滴,在后续油滴检测时发挥作用
3.怎么确定顺序,找max?
即确定半径的顺序
A:如果有方法提前确定,那就是贪心策略;
如果没有,那就是搜索,即列举出所有情况,然后选最优。
const double pi = 3.1415926535;
bool s[10];
double x[10], y[10], r[10], xa, xb, ya, yb, ansmax;
int n;
double cal(int i) {
double s1 = min(abs(x[i] - xa), abs(x[i] - xb));
double s2 = min(abs(y[i] - ya), abs(y[i] - yb));
double ans = min(s1, s2);
for (int j = 1; j <= n; j++) {
if (i != j && s[j]) {//从头开始遍历,只有不是本身以及油滴已经扩展过了,才进行判断
//否则如果没扩展过,就没r,自然也判断不了
double d = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
ans = min(ans, max(d - r[j], 0.0));//d-r[j]是这个点的油滴相对于j油滴所能允许扩展的最大半径
}
}
return ans;
}
void dfs(int k, double sum) {
if (k > n) {
ansmax = max(ansmax, sum);
return;
}
for (int i = 1; i <= n; i++) {
if (!s[i]) {
r[i] = cal(i);
s[i] = 1;//通过标记s数组,对后续的油滴半径确定造成影响
dfs(k + 1, sum + r[i] * r[i] * pi);
s[i] = 0;
}
}
}
double ss;
cin >> n;
cin >> xa >> ya >> xb >> yb;
ss = abs(xa - xb) * abs(ya - yb);
for (int i = 1; i <= n; i++) {
cin >> x[i] >> y[i];
}
dfs(1, 0);
cout << int(ss - ansmax + 0.5);//四舍五入的好方法
四舍五入
1.怎么识别闭合圈?
A:用两个数组实现,一个是原数组数据,不要动
一个是用来修改1之外的0,修改通过搜索的方式(dfs,bfs),遇到0就修改为1,直到周围全是1
这样,对于1围起来的0就修改不了,因为根本访问不到里面,而只能把能访问到的(即1之外的)0全修改成1
2.对于1围起来的0和1之外的0怎么区分?
A:通过另一个数组
3.怎么修改1围起来的0?
A:遍历另一个数组,如果访问的位置依然是0,就说明这是1围起来的0,没有被修改过,这时就要输出2,其他情况一律输出原数组的原数据
void dfs(int p, int q) {
a[p][q] = 1;
for (int i = 1; i <= 4; i++) {
int newp = p + dx[i], newq = q + dy[i];
if (newp >= 1 && newp <= n && newq >= 1 && newq <= n && a[p][q] == 0) {
dfs(newp, newq);
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> b[i][j];
if (b[i][j] == 0) {
a[i][j] = 0;
}
else {
a[i][j] = 1;
}
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (a[i][j] == 0) {
cout << 2 << " ";
}
else {
cout << b[i][j] << " ";
}
}
cout << endl;
}
想法:计一个方向数组,然后从初始点,不断往后走,用cnt记录当前步数,并把这个步数和当前位置上的数作比较取min,最后输出就行
用bfs,有天然优势
用dfs,会爆栈,没找到问题与解决方法
#include
#include
#include
#include
#include
#include
using namespace std;
int dx[8] = { 2,1,-1,-2,-2,-1,1,2 }, dy[8] = { 1,2,2,1,-1,-2,-2,-1 };
int cnt = 0,m,n,x,y;
int map[405][405];
struct node {
int x, y;
node(int a, int b) :x(a), y(b) {};
};
//void dfs(int x, int y) {
// map[x][y] = cnt;
// for (int i = 0; i < 8; i++) {
// int newx = x + dx[i], newy = y + dy[i];
// if (newx >= 1 && newx <= n && newy >= 1 && newy <= m&& (cnt + 1 < max(map[newx][newy], -1)) || map[newx][newy] == -1) {
// cnt++;
// dfs(newx, newy);
// cnt--;
// }
// }
//}
//cin >> m >> n >> x >> y;
//memset(map, -1, sizeof(map));
//dfs(x, y);
//for (int i = 1; i <= n; i++) {
// for (int j = 1; j <= m; j++) {
// cout << map[i][j] << " ";
// }
// cout << endl;
//}
bool use[405][405];
int main() {
cin >> n >> m;
cin >> x >> y;
queueq;
q.push(node(x, y));
use[x][y] = 1;
while (!q.empty()) {
int num = q.size();
for (int k = 1; k <= num; k++) {
node cur = q.front();
q.pop();
map[cur.x][cur.y] = cnt;
for (int i = 0; i < 8; i++) {
int newx = cur.x + dx[i], newy = cur.y + dy[i];
if (newx >= 1 && newx <= n && newy >= 1 && newy <= m && !use[newx][newy]) {
q.push(node(newx, newy));
use[newx][newy] = 1;
}
}
}
cnt++;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (use[i][j]) { cout << map[i][j] << " "; }
else { cout << -1 << " "; }
}
cout << endl;
}
return 0;
}