week 10还是图论,但是这周的题目含参了不少之前学过的其他知识点。这周还新学了两个知识。
Einstein学画画
看完题想了一下,这感觉纯纯的数学问题啊,七桥嘛。可惜我忘了七桥怎么解(悲),于是上网搜了一下数学上的解法。总而言之,只有2个奇点才能1笔画完。如果每多出两个奇点,那么画的次数就会+1,而联通图只可能有偶数个奇点。再加一个三个都不是奇点但是能一笔画情况的特判,这样就能够得出答案了。
代码:
#include<bits/stdc++.h>
using namespace std;
int n, m, cnt[1005], ans;
int main() {
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int x, y;
cin >> x >> y;
cnt[x]++;
cnt[y]++;
}
for (int i = 1; i <= n; i++) {
if (cnt[i] & 1 == 1)
ans++;
}
if (ans == 0)
puts("1");
else
{
ans/=2;
cout<<ans<<endl;
}
return 0;
}
和根植物
这道题还算简单,用深搜就能做出来 。那么如何使用深搜呢?只要把不同和根植物区分开即可。我因此用了结构体来存不同的和根植物。同时,要建立visit数组方便搜索。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
int head[maxn];
int cnt;
bool vis[maxn];
struct Edge
{
int u,v,next;
}edge[maxn*2];
void addEdge(int u,int v)
{
edge[cnt].u=u;
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
memset(vis,1,sizeof(vis));
cnt=0;
}
void dfs(int u)
{
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(vis[v]==0) {
continue;
}
dfs(v);
}
}
int main()
{
int n,m,k;
init();
cin>>n>>m>>k;
for(int i=0,u,v;i<k;i++)
{
cin>>u>>v;
addEdge(u,v);
addEdge(v,u);
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(vis[j+(i-1)*m])
{
dfs(j+(i-1)*m);
ans++;
}
}
}
cout<<ans<<endl;
return 0;
}
奶酪
这道题还跟上题一样,用深搜。题目的意思就是从底部找到能通往顶部的一条路,其中每个相切或相交的空心球就是一个节点。
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1010;
struct cir
{
double x,y,z;
bool operator<(const cir &cpr)const
{
return z<cpr.z;
}
}p[MAXN];
bool fnd=0;
int n;double h,r;
bool vis[MAXN];
double dist(double x1,double y1,double z1,double x2,double y2,double z2)
{
return sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)+(z2-z1)*(z2-z1));
}
void dfs(cir now,int num)
{
if(now.z+r>=h)
{
fnd=1;
return;
}
vis[num]=1;
for(int i=1;i<=n;i++)
{
if(fnd)
return;
if(!vis[i]&&dist(now.x,now.y,now.z,p[i].x,p[i].y,p[i].z)<=r*2)
dfs(p[i],i);
}
//vis[num]=0;
}
int main()
{
freopen("cheese.in","r",stdin);
freopen("cheese.out","w",stdout);
int T;scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
memset(p,0,sizeof(p));fnd=0;
cin>>n>>h>>r;
for(int i=1;i<=n;i++)
cin>>p[i].x>>p[i].y>>p[i].z;
std::sort(p+1,p+n+1);
for(int i=1;i<=n;i++)//lower
if(p[i].z-r<=0)
dfs(p[i],i);
if(fnd)
puts("Yes");
else
puts("No");
}
return 0;
}
灾后重建
这道题运用到了上周学习的floyd算法,但是解题的主题部分却是再之前的动态规划专题。这道题的转移方程是f[k][i][j] = min( f[k-1][i][j], f([k-1][i] [k])+f[k-1][k][j] )。其中f[k][i][j]表示路径除开起点i与终点j,只经过前k个点中的某些 点,从i到j的最小值。
代码:
#include<bits/stdc++.h>
using namespace std;
bool b[201];
int n,m,x,y,z,q,t[201],f[201][201];
int from[50001],to[50001],day[50001];//questions;
int main()
{
memset(f,0x7f,sizeof(f));
cin>>n>>m;
for (int i=0; i<n; i++)
f[i][i]=0;//初始化
for (int i=0; i<n; i++)//注意从0开始
cin>>t[i];
for (int i=1; i<=m; i++)
{
cin>>x>>y>>z;
f[x][y]=f[y][x]=z;
}
cin>>q;
int tot=0;
for (int i=1; i<=q; i++)
{
cin>>from[i]>>to[i]>>day[i];
}
for (int l=1; l<=q; l++)
{
for (int k=0; k<n; k++)
if (t[k]<=day[l]&&!b[k])
{
b[k]=1;
for (int i=0; i<n; i++)
for (int j=0; j<n; j++)
if (f[i][j]>f[i][k]+f[k][j]&&i!=j&&i!=k&&k!=j&&f[i][k]<0x7f7f7f7f&&f[k][j]<0x7f7f7f7f)
f[i][j]=f[i][k]+f[k][j];
}
if (t[from[l]]<=day[l]&&t[to[l]]<=day[l]&&f[from[l]][to[l]]!=0x7f7f7f7f)
cout<<f[from[l]][to[l]]<<endl;
else printf("-1\n");
}
return 0;
}
聪明的猴子
这道题一开始看的时候没想到怎么做,后面在学习通又看了遍最小生成树后有了点思路。
题意是给出所有猴子的最大跳跃距离,然后给你很多树,让你看看有几只猴子比这棵生成树上的所有边的长度都长。思路是把两个点之间的距离算出来,记录下最大的边,和每只猴子的跳跃距离比较一下,如果跳跃距离大就ans++。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;
long long n,jump[600],x[1200],y[1200],cnt,head[1200],dis[1200],max_dis=0;
bool vis[1200];
struct{
long long v,nxt,w;
}e[2001000];//链式前向星
void adde(long long u,long long v,long long w){
e[++cnt].v=v;
e[cnt].w=w,e[cnt].nxt=head[u];
head[u]=cnt;
}//建边
void prim(){
typedef pair<long long,long long>p;
priority_queue<p,vector<p>,greater<p> >q;
long long chosen_point_num=1,u=1;
memset(dis,0x3f,sizeof(dis));
for(long long i=head[u];i;i=e[i].nxt){
long long v=e[i].v;dis[v]=min(dis[v],e[i].w);
q.push(make_pair(dis[v],v));
}
while(++chosen_point_num<=n){
vis[u]=1;
while(vis[q.top().second])q.pop();
max_dis=max(max_dis,q.top().first);
u=q.top().second;q.pop();
for(long long i=head[u];i;i=e[i].nxt){
long long v=e[i].v;
if(vis[v]==0&&dis[v]>e[i].w){
dis[v]=e[i].w;
q.push(make_pair(dis[v],v));
}
}
}
}
int main(){
long long m,ans=0;cin>>m;
for(long long i=1;i<=m;i++){
scanf("%lld",&jump[i]);
jump[i]*=jump[i];
}
cin>>n;
for(long long i=1;i<=n;i++)
scanf("%lld%lld",&x[i],&y[i]);
for(long long i=1;i<=n;i++)
for(long long j=i+1;j<=n;j++){
long long tmp=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
adde(i,j,tmp),adde(j,i,tmp);
}
prim();
for(int i=1;i<=m;i++)if(jump[i]>=max_dis)ans++;
cout<<ans;
return 0;
}