//Satellite Photographs
//农民约翰购买了卫星照片$W \times H$他的农场像素$(1 \le W \le 80, 1 \le H \le 1000)$并希望确定最大的“连续”(连接)牧场。
//当牧场中的任何一对像素可以通过遍历作为牧场一部分的相邻垂直或水平像素来连接时,牧场是连续的。
//每张照片都经过数字增强,将牧场区域显示为星号 (),将非牧场区域显示为句点 ()。*.
//这是一个$10 \times 5$卫星照片示例:
//..*.....**
//.**..*****
//.*...*....
//..****.***
//..****.***
//这张照片显示了三个连续的牧场$4$,$16$和$6$像素。帮助FJ在他的每张卫星照片中找到最大的连续牧场。
//此题在于dfs不回溯,要知道dfs是一条路走到黑,当我们在第一行或者第二行找到第一个起点时,会一直走下去
//此时,直到dfs不能走了,这条路才结束.当我们在第二行遇到第一行走的点时,一定比第一行的点小,故不需要再走,不需要回溯.
//就比如样例,所有最大的点,只能从第一行的四个点找,后者都是被走过的,只要被走过,不是起点,那么就肯定没有起点多,故不需要回溯.
#include<bits/stdc++.h>
using namespace std;
const int W=1000;
const int H=1000;
bool vis[W][H];
int n,m,sum,mmax;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
char mp[W][H];
void dfs(int x,int y)
{
sum++;
vis[x][y]=true;
for(int i=0;i<4;i++)
{
int x1=x+dx[i],y1=y+dy[i];
if(!vis[x1][y1]&&x1>=0&&x1<m&&y1>=0&&y1<n&&mp[x1][y1]=='*')
dfs(x1,y1);
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
cin>>mp[i][j];
mmax=-1;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
if(!vis[i][j]&&mp[i][j]=='*')
{
sum=0;
dfs(i,j);
mmax=max(sum,mmax);
}
cout<<mmax;
}
//P2895 [USACO08FEB]Meteor Shower S
//题目链接:https://www.luogu.com.cn/problem/P2895;
//本题又是一次新的看法,三个变量颠覆我之前的bfs,之前的bfs都是从0,0开始,没有时间限制;
//这次每个点都会在一定时间内被覆盖,所以需要开一个数组time1[]来储存下落的时间,当我们下一步要走的时间小于这个时间,并且下个点可以走,我们就走;
//time1[]的妙处还在于,可以预知哪个点在以后是危险的,所以time1只要不等于-1,这个点不可能是安全点.只有我们走到一个time=-1的点,这个点才是安全点.
//与之前bfs不同之处在于,多了一个判断条件,就因为这个判断条件搞得思路全无.
#include<bits/stdc++.h>
using namespace std;
const int N=50005;
bool vis[305][305];
int n,dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int time1[305][305];
struct node
{
int x,y,t;
};
void bfs()
{
queue<node>que;
vis[0][0]=true;
node str;
str.x=0,str.y=0,str.t=0;
que.push(str);
while(!que.empty())
{
node now=que.front();
que.pop();
for(int i=0;i<4;i++)
{
node next;
next.x=now.x+dx[i];
next.y=now.y+dy[i];
next.t=now.t+1;
if(next.x>=0&&next.y>=0&&(now.t+1<time1[next.x][next.y]||time1[next.x][next.y]==-1)&&!vis[next.x][next.y])
{
que.push(next);
vis[next.x][next.y]=true;
if(time1[next.x][next.y]==-1)
{
cout<<next.t<<endl;
return;
}
}
}
}
cout<<"-1";
}
int main()
{
cin>>n;
memset(time1,-1,sizeof time1);
for(int i=0;i<n;i++)
{
int a,b,t;
cin>>a>>b>>t;
if(t<time1[a][b]||time1[a][b]==-1)//细节,所存的时间必须要是最小的时间,因为有可能一个坑被砸两次;
time1[a][b]=t;
for(int i=0;i<4;i++)
{
int x=a+dx[i],y=b+dy[i];
if(x>=0&&y>=0&&(t<time1[x][y]||time1[x][y]==-1))
time1[x][y]=t;
}
}
bfs();
return 0;
}
//选数,地址:https://www.luogu.com.cn/problem/P1036;
//这个题让我想起了算24,但用算24做感觉怎么都做不出来,实在不行又去看题解了
//dfs要灵活使用计数器,判断条件等;
#include<bits/stdc++.h>
using namespace std;
int n,k,res=0;
int a[25];
bool isPrime(int x){//csdn上搜的最快的判断素数的方法,我怕时间不够;
if (x == 1) return false;
if (x == 2 || x == 3) return true;
if (x % 6 != 5 && x % 6 != 1) return false;
for (int i = 5; i < sqrt(x); i+=6){
if (x % i == 0 || x % (i + 2) == 0)
return false;
}
return true;
}
void dfs(int start,int num,int sum)//分别是:从哪开始找,找了多少数,现在的和是多少;(当时就看了这一行我就知道怎么求解了,就跑去编代码了)
{
if(num==k)
{
if(isPrime(sum))
res++;
return;
}
for(int i=start;i<n;i++)//从开始的位置,向后找(为什么要这样呢?因为从0开始,0会遍历整个数组,这个就是开始位置的妙处);
dfs(i+1,num+1,sum+a[i]);//记录开始的位置;
}
int main()
{
cin>>n>>k;
for(int i=0;i<n;i++)
cin>>a[i];
dfs(0,0,0);
cout<<res;
return 0;
}
//P2036 [COCI2008-2009#2] PERKET
//https://www.luogu.com.cn/problem/P2036
//你有 n 种可支配的配料。对于每一种配料,我们知道它们各自的酸度s 和苦度b。当我们添加配料时,总的酸度为每一种配料的酸度总乘积;总的苦度为每一种配料的苦度的总和。
//众所周知,美食应该做到口感适中,所以我们希望选取配料,以使得酸度和苦度的绝对差最小。
//另外,我们必须添加至少一种配料,因为没有任何食物以水为配料的。
//看题解都说是经典bfs,很水的一道题,但我却没什么想法,看了一眼题解,看到分成添加和不添加两条路来走我就想起来了,确实简单,立马想起来八皇后的问题
//不要忘记dfs还有双路线可以走,走单路线走多了忘记搜或者不搜这个选项了
#include<bits/stdc++.h>
using namespace std;
const int N=10;
int n,minn=0x7fffffff;
int s[10],k[10];
void dfs(int num,int sums,int sumk)
{
if(num==n)//八皇后问题,无论你放不放,反正到最后你搜到最后一组才能算结束.
{
if(sums==1&&sumk==0)
return;
int ans=abs(sums-sumk);
minn=min(minn,ans);
return;
}
dfs(num+1,sums,sumk);//不添加
dfs(num+1,sums*s[num],sumk+k[num]);//添加
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>s[i]>>k[i];
dfs(0,1,0);//食物编号,酸度总和,苦度总和;
cout<<minn;
return 0;
}
//问题 D: Sticks
//链接:https://oj.ytu.edu.cn/problem.php?cid=4167&pid=3;
//此题又是一种新的搜索方法,不算新,但是其中有一点需要注意
///运用了大量的剪枝技巧;
///详细说明地址:https://blog.csdn.net/Helinshan/article/details/119078957
#include<bits/stdc++.h>
using namespace std;
const int N=70;
int n,res,len,x,a[N],sum,cnt;
bool stick[N];
bool cmp(int a,int b)
{
return a>b;
}
bool dfs(int num,int l,int nextpos)///已经拼了几节木棍了,现在拼接的长度是多少,下一次拼接的小木棍的位置
///定义bool类型搜索函数,这样就不用担心状态问题了
{
if(num==x) return true;
if(l==len) return dfs(num+1,0,0);
int fail=0;
for(int i=nextpos;i<cnt;i++)
{
if(!stick[i]&&l+a[i]<=len&&a[i]!=fail)///剪枝五,如有相同长度的木棍,那不用想肯定也是不能和l长度的木棍拼接的;
{
stick[i]=true;
if(dfs(num,l+a[i],i+1)) return true;
stick[i]=false;///剪枝四,回溯标记,这样不用每一次dfs搜索用一次memset(听说memset巨慢
fail=a[i];
if(l==0||l==len) return false;
while(i<cnt-1&&a[i+1]==a[i]) i++; //// 跳过相同长度的木棒
if(a[i]==len-l) return false; //// 优先选择长度较小的木棒拼接
}
}
return false;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int t;
scanf("%d",&t);
if(t>50) continue;///剪枝三,存在错误数据,可以直接跳过;
a[cnt++]=t;
sum+=t;
}
stable_sort(a,a+cnt,cmp);///剪枝一,从大到小排序,避免重复拼接;
for(int i=a[cnt-1];i<=sum;i++)///剪枝二,从小到大进行搜索(二分或许更快?)
{
if(sum%i!=0) continue;
x=sum/i;
len=i;
if(len==1&&sum!=n) continue; //// 特判
if(dfs(0,0,0))
{
cout<<len;
break;
}
}
return 0;
}
//问题 I: DNA
//链接:https://oj.ytu.edu.cn/problem.php?cid=4167&pid=8;
//本题我思路是正确的,那么在哪里出错了呢,就是字符串的拼接问题上;
///字符串拼接是这题的难点所在,还有必须要剪枝,不然会超时(在YTU上);
#include<bits/stdc++.h>
using namespace std;
const int N=16;
int n,t,res;
int a[N][N];
string s[N];
bool vis[N];
int work(string a,string b)
{
for(int i=0;i<a.size();i++)
{
if(b.find(a.substr(i))==0)///substr函数是截取从i开始一直到结尾的串,用此方法可以算出两者合并所需要减去的长度;
return a.size()-i;
}
}
void dfs(int num,int len,int id)
{
if(len>=res) return;
if(num==n)
{
res=min(res,len);
return;
}
for(int i=0;i<n;i++)
{
if(!vis[i])
{
vis[i]=true;
dfs(num+1,len+s[i].size()-a[id][i],i);
vis[i]=false;
}
}
return;
}
int main()
{
cin>>t;
while(t--)
{
res=0x3f3f3f;
memset(a,0,sizeof a);
memset(vis,false,sizeof vis);
cin>>n;
for(int i=0;i<n;i++)
{
cin>>s[i];
for(int j=0;j<i;j++)
{
if(s[j].find(s[i])!=-1)
{
i--,n--;
break;
}
if(s[i].find(s[j])!=-1)
{
swap(s[i],s[j]);
i--,n--;
break;
}
}///剪枝,剔除字串和重复串,很有效率,快了10倍.
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
if(i==j) continue;
a[i][j]=work(s[i],s[j]);///难点;
}
for(int i=0;i<n;i++)
{
vis[i]=true;
dfs(1,s[i].size(),i);
vis[i]=false;
}
cout<<res<<endl;
}
return 0;
}
// 鸣人与佐助
//链接:http://noi.openjudge.cn/ch0205/6044/
///本题的思路大致与标准bfs一致,但有一点需要注意
///本题具有查克拉限制,又是一个限制条件,与之类似具有限制的条件的是洛谷的流星陨石找安全
///由于查克拉限制,我们有可能多次路过这个点,而此时的查克拉的数目不一样,也就是不同的状态
///所以我们的bool 判断要上升到三维,上代码
#include<bits/stdc++.h>
using namespace std;
const int N=205;
int n,m,c;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
bool vis[N][N][15];
char mp[N][N];
struct node
{
int x,y,ckl,step;///相较于往常多加了查克拉的量;
};
void bfs(int i,int j)
{
queue<node>que;
node str;
str.ckl=c,str.x=i,str.y=j,str.step=0;
que.push(str);
while(!que.empty())
{
node now=que.front();
que.pop();
if(mp[now.x][now.y]=='+')
{
cout<<now.step;
return;
}
for(int i=0;i<4;i++)
{
node next;
next.x=now.x+dx[i],next.y=now.y+dy[i];
if(next.x>=0&&next.x<n&&next.y>=0&&next.y<m)
{
if(mp[next.x][next.y]=='#')
{
if(now.ckl>0&&!vis[next.x][next.y][now.ckl-1])
{
next.ckl=now.ckl-1;
next.step=now.step+1;
vis[next.x][next.y][now.ckl-1]=true;
que.push(next);
}
}
if(mp[next.x][next.y]=='*'&&!vis[next.x][next.y][now.ckl])
{
next.step=now.step+1;
vis[next.x][next.y][now.ckl]=true;
next.ckl=now.ckl;
que.push(next);
}
if(mp[next.x][next.y]=='+')//注意,这个是容易忘记判断的点,我就纳闷了1分钟我错在哪.哈哈
{
next.ckl=now.ckl;
next.step=now.step+1;
que.push(next);
}
}
}
}
cout<<"-1";
}
int main()
{
cin>>n>>m>>c;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>mp[i][j];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(mp[i][j]=='@')
{
vis[i][j][c]=true;
bfs(i,j);
break;
}
return 0;
}
//洛谷:P1825 [USACO11OPEN]Corn Maze S
///这个题坑人的地方在于传送门进去之后有可能四面都是墙,就需要回去,所以传送门不需要标记
///特别注意的是,需要先判断传送门,在走路,如果先走再判断传送门很容易进入死循环,我就这样卡在60不动了
#include<bits/stdc++.h>
using namespace std;
const int N=305;
int n,m;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
char mp[N][N];
bool vis[N][N];
struct node
{
int x,y,step;
bool operator<(const node &w)const
{
return step>w.step;
}
};
void goto_another(int &nx,int &ny,int k)//goto_another函数用于寻找另一个传送门,nx、ny代表当前点的坐标,记得要加上取地址符'&',因为每当贝西踏入一个传送门,它就会立即被传送至另一个传送门,不能在原地停留
{
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(mp[i][j]==mp[nx][ny]&&(i!=nx||j!=ny))//如果a[i][j]这个点的是一个与a[nx][ny]相同的传送门,并且a[i][j]与a[nx][ny]不是同一个点
{
nx=i;//改变当前坐标,将贝西强行移动至另一个传送门处
ny=j;
return ;//告辞
}
}
}
}
void bfs(int i,int j)
{
priority_queue<node>que;
node str;
str.x=i,str.y=j,str.step=0;
que.push(str);
while(!que.empty())
{
node now=que.top();
que.pop();
if(mp[now.x][now.y]=='=')
{
cout<<now.step;
return;
}
if(mp[now.x][now.y]>='A'&&mp[now.x][now.y]<='Z')//特判部分,如果当前点是一个传送门,那么就传送至另一个传送门
{
goto_another(now.x,now.y,now.step);///预先处理,这样就不需要考虑传送之后出bug了
}
for(int i=0;i<4;i++)
{
node next;
next.x=now.x+dx[i];
next.y=now.y+dy[i];
if(next.x>=0&&next.x<n&&next.y>=0&&next.y<m&&!vis[next.x][next.y]&&mp[next.x][next.y]!='#')
{
vis[next.x][next.y]=true;
next.step=now.step+1;
que.push(next);
}
}
}
}
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
cin>>mp[i][j];
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(mp[i][j]=='@')
{
vis[i][j]=true;
bfs(i,j);
break;
}
}
//洛谷:https://www.luogu.com.cn/problem/P1874
///虽然在动态规划里面,但还是用dfs做出来了,dfs好简单啊,但我没想到
///还是对dfs理解不透
///dfs要搞清楚如何往下深搜,也就是dfs函数里面的赋值问题,不止一次碰到过这种类型的广搜了
///接下来看代码
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
string s;
///从0个加号开始枚举,加号最多是n-1个加号,不可能有n个数用n个加号
int n,res,k,len;
bool flag=false;
void dfs(int num,int restpos,int nowpos,int restadd)///分别是 当前所加得数总和-上一次加号的位置-现在想加数的位置-剩下的加号数量
{
if(nowpos==n+1)
return;
if(restadd==0)
{
int x=0;
for(int i=restpos;i<=n;++i)
x=x*10+s[i]-'0';///进位,例如12345,2是restpos,4是nowpos,那么我们就要加24,所以要进位
if(num+x==res)
flag=true;
return;
}
if(flag) return;
int x=0;
for(int i=restpos;i<=nowpos;++i)
x=x*10+s[i]-'0';
dfs(num+x,nowpos+1,nowpos+1,restadd-1);
dfs(num,restpos,nowpos+1,restadd);
}
int main()
{
cin>>s>>res;
n=s.size()-1;
for(int i=0;i<=n;i++)
{
dfs(0,0,0,i);
if(flag)
{
cout<<i;
return 0;
}
}
cout<<"-1";///易忘点
return 0;
}
//Saving Tang Monk
//https://oj.ytu.edu.cn/problem.php?cid=4181&pid=8
///优先队列搜索题,这个题的难点在于
///1.有蛇条件限制,而且路过蛇的话,时间要+2,并且蛇不会被杀死,所以很有可能重复路过,要考虑优先队列
///2.钥匙限制,这个钥匙限制让我想到了鸣人与佐助的那道查克拉题,由于钥匙限制,我们要开一个三维状态的标记数组
///3.搜索路程过多,其中队列的状态不能随便修改
///优化是肯定还能优化的,但太累了,忙活了俩小时才ac,我去找chatgtp优化一下
//下面是代码
#include<bits/stdc++.h>
using namespace std;
const int N=110;
char mp[N][N];
int n,m,res;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
bool vis[N][N][11];
struct node
{
int x,y,step,key,s;
bool operator<(const node&w)const///内嵌函数优先队列
{
return step>w.step;
}
};
void bfs(int i,int j)
{
priority_queue<node>que;
node str;
str.x=i,str.y=j;str.step=str.key=str.s=0;
que.push(str);
vis[i][j][0]=true;
while(!que.empty())///经典
{
node now=que.top();
que.pop();
if(mp[now.x][now.y]=='T'&&now.key==m)///由于我们是优先队列,所以第一个出来的肯定是步数最小的,直接输出结束就可以
{
cout<<now.step<<endl;
return;
}
for(int i=0;i<4;i++)
{
node next;
next.x=now.x+dx[i],next.y=now.y+dy[i];
if(next.x>=0&&next.x<n&&next.y>=0&&next.y<n&&!vis[next.x][next.y][now.key]&&mp[next.x][next.y]!='#')
{
if(mp[next.x][next.y]=='S')
{
vis[next.x][next.y][now.key]=true;
next.key=now.key;
next.step=now.step+2;
que.push(next);
}
else
{
if(mp[next.x][next.y]==now.key+1+'0')///特别注意,这里不要使用 now.step+=1,会改变now.key的状态,有可能重复走,所以要分情况;
{
next.key=now.key+1;
vis[next.x][next.y][now.key]=true;
next.step=now.step+1;
que.push(next);
}
else
{
next.key=now.key;
vis[next.x][next.y][now.key]=true;
next.step=now.step+1;
que.push(next);
}
}
}
}
}
cout<<"impossible"<<endl;
return;
}
int main()
{
while(cin>>n>>m&&n!=0)
{
res=0x3f3f3f;
memset(vis,false,sizeof vis);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) cin>>mp[i][j];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(mp[i][j]=='K')
{
bfs(i,j);
break;
}
}
return 0;
}
//ROADS
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,k,r,t;
int first[N],nex[N],u[N],v[N],w[N],c[N];
int dis[105][N];
bool vis[105][N];
struct node
{
int num,cost,dis;
bool operator<(const node&w)const
{
return dis>w.dis;
}
};
void dijkstra()
{
memset(dis,0x3f3f3f,sizeof dis);
priority_queue<node>que;
node a,b;
a.num=1;
a.dis=0;
a.cost=0;
que.push(a);
while(!que.empty())
{
a=que.top();
que.pop();
if(a.num==n)
{
cout<<a.dis;
return;
}
for(int i=first[a.num];i!=-1;i=nex[i])
{
int cost=a.cost+c[i];
if(cost>k) continue;
if(dis[v[i]][cost]>a.dis+w[i])
{
dis[v[i]][cost]=a.dis+w[i];
b.num=v[i];
b.dis=dis[v[i]][cost];
b.cost=cost;
que.push(b);
}
}
}
cout<<-1;
}
int main()
{
memset(first,-1,sizeof first);
cin>>k>>n>>r;
for(int i=1;i<=r;i++)
{
cin>>u[i]>>v[i]>>w[i]>>c[i];
nex[i]=first[u[i]];
first[u[i]]=i;
}
dijkstra();
}
//https://www.luogu.com.cn/problem/P1077
///记忆化搜索