链接:https://www.jisuanke.com/contest/7331?view=challenges
B Pokemon Go Go
题意:在100x100的方格纸上有n只精灵(n<=20),它们都有自己的名字或者是种类,你需要抓到所有种类的精灵(每种只能一个,种类数不超过15),问你从00点出发再回到00点你经过的最小距离是多少。
种类数m<=15,n<=20,不大的数据范围非常适合状压dp 复杂度刚好是0(n ^ 2 * 2 ^ m)
既然每种种类只能有一个那状态就表示种类,那就需要处理一下每个精灵的种类了,编个1开始的号,那么第二个下标表示啥呢,种类肯定不行了(你只知道从那个种类过来的但是是那个点呢,一个种类可以有许多点的)那就用点呗,太菜了没想通这一点。。。最后在满状态里取最小值就可以了。需要注意点的坐标可能为负。
#include<iostream>
#include<cstring>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=21;
int n,x[N],y[N],cnt,sz[N];
map<string,int> mp;
int dp[1<<N][N];
int dis(int i,int j)
{
return abs(x[i]-x[j])+abs(y[j]-y[i]);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
string s;
cin>>x[i]>>y[i]>>s;
if(!mp[s])//处理种类
{
mp[s]=++cnt;
sz[i]=cnt;
}
else sz[i]=mp[s];
}
memset(dp,0x3f,sizeof dp);
for(int i=0;i<(1<<cnt);i++)
{
for(int j=1;j<=n;j++)
{
if((i&(1<<(sz[j]-1)))==0) continue;
if(i==(1<<(sz[j]-1)))
{
dp[1<<(sz[j]-1)][j]=dis(0,j);
continue;
}
for(int k=1;k<=n;k++)
if((i&(1<<(sz[k]-1)))&&sz[j]!=sz[k])
dp[i][k]=min(dp[i][k],dp[i-(1<<(sz[k]-1))][j]+dis(j,k));
}
}
int ans=0x3f3f3f3f;
for(int i=1;i<=n;i++)
ans=min(dp[(1<<cnt)-1][i]+dis(0,i),ans);
cout<<ans;
return 0;
}
G dfs大水题
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100010;
int d[8][2]={0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,-1,-1,1};
int n,m,cnt;
char s[200][200];
bool st[200][200];
void dfs(int x,int y)
{
st[x][y]=1;
for(int i=0;i<8;i++)
{
int dx=x+d[i][0],dy=d[i][1]+y;
if(!st[dx][dy]&&s[dx][dy]=='#')
dfs(dx,dy);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%s",s[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(!st[i][j]&&s[i][j]=='#')
{
dfs(i,j);
cnt++;
}
printf("%d",cnt);
return 0;
}
H (找规律)
没一次变只能变最下面的O,就是说每次到哪一个O时一定是O下面全是Z,变一次之后这个位置下面就全是O 了,所以变低i位就是变前i-1位的和在加1,所以求个前缀和就好了其实最后打表会发现第i位就是 1<<i ;(1<<60应该没爆ll啊,不知道为啥错了,直接高精度就好了)
#include<vector>
#include<iostream>
using namespace std;
typedef unsigned long long ull;
const int N=100010;
int n,m,cnt;
vector<int> sum[100],a[100];
vector<int> add(vector<int> &A, vector<int> &B)
{
if (A.size() < B.size()) return add(B, A);
vector<int> C;
int t = 0;
for (int i = 0; i < A.size(); i ++ )
{
t += A[i];
if (i < B.size()) t += B[i];
C.push_back(t % 10);
t /= 10;
}
if (t) C.push_back(t);
return C;
}
char s[100];
int main(){
cin>>n;
for(int i=n;i;i--)
cin>>s[i];
vector<int> ans,res;
res.push_back(1);
for(int i=1;i<=n;i++)
{
a[i]=add(sum[i-1],res);
sum[i]=add(a[i],sum[i-1]);
if(s[i]=='O')
{
ans=add(ans,a[i]);
}
}
for(int i=ans.size()-1;i>=0;i--)
printf("%d",ans[i]);
return 0;
}
I 每到一步求一下向两边走的步数最小值就可以了,刚开始看错题意了,wa了好久
#include<vector>
#include<iostream>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const int N=100010;
int n;
const double pi=3.14159265358;
char s[100];
map<char,int> mp;
bool check(char c)
{
if(c==' '||(c>='A'&&c<='Z'))return 0;
else return 1;
}
int main(){
for(int i=1;i<=26;i++)
mp[char(i+'A'-1)]=i;
mp[' ']=27;
cin>>n;
getchar();
double res=pi*60/28.0;
while(n--)
{
string s;
vector<int> ve;
getline(cin,s);
int cnt=0;
for(int i=0;i<s.size()-1;i++)
{
if(check(s[i])&&check(s[i+1])) continue;
else if(check(s[i]))
{
cnt+=min(28-mp[s[i+1]],mp[s[i+1]]);
}
else if(check(s[i+1]))
{
cnt+=min(28-mp[s[i]],mp[s[i]]);
}
else
{
int x=abs(mp[s[i]]-mp[s[i+1]]);
cnt+=min(x,28-x);
}
}
double ans=(res*(cnt))/15.0+s.size();
printf("%.8lf
",ans);
}
return 0;
}
J 最小生成树模板题
#include<vector>
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ull;
const int N=2510,INF=0x3f3f3f3f;
int n,g[N][N],dist[N];
bool st[N];
vector<pair<int,int> > ve;
map<int,int> mp;
void prim()
{
memset(dist, 0x3f, sizeof dist);
for (int i = 0; i < n; i ++ )
{
int t = -1;
for (int j = 1; j <= n; j ++ )
if (!st[j] && (t == -1 || dist[t] > dist[j]))
t = j;
if (i && dist[t] == INF) return ;
if (i)ve.push_back({mp[t],t});
st[t] = true;
for (int j = 1; j <= n; j ++ )
if(dist[j] > g[t][j])
{
dist[j]=g[t][j];
mp[j]=t;
}
}
return ;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>g[i][j];
prim();
for(int i=0;i<ve.size();i++)
cout<<ve[i].first<<' '<<ve[i].second<<endl;
return 0;
}