A石油采集
分析:二分匹配。
一个油田只能够和一个油田匹配被瓢走 ,所以我们 对每一个油田 遍历其四周,如果也有油田,那么就建立边表示有可能匹配。 最后匈牙利算法求最大匹配就好了。
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 50*50+11;
const int M = 1E6+11;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const LL inff = 0x3f3f3f3f3f3f3f3f;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
while(ch<='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
/*-------------------------*/
struct Edge {
int from,to,next;
}edge[M];
int head[N],top;
void init(){
memset(head,-1,sizeof(head));
top=0;
}
void addedge(int a,int b){
Edge e={a,b,head[a]};
edge[top]=e; head[a]=top++;
}
int used[N],pipei[N];
bool Find(int x){
for(int i=head[x];i!=-1;i=edge[i].next){
Edge e=edge[i];
if(!used[e.to]){
used[e.to]=1;
if(pipei[e.to]==-1 || Find(pipei[e.to])){
pipei[e.to]=x;
return true;
}
}
}
return false;
}
int to[4][2]={0,1,0,-1,1,0,-1,0};
bool mp[N][N];
int solve(int n){
memset(pipei,-1,sizeof(pipei));
int ans=0;
for(int i=1;i<=n*n;i++){
memset(used,0,sizeof(used));
if(Find(i) ) ans++;
}
return ans;
}
int main(){
int T;scanf("%d",&T);int zz=1;
while(T--){
init();
memset(mp,0,sizeof(mp));
int n;scanf("%d",&n);
for(int i=1;i<=n;i++){
string s;cin>>s;
for(int j=0;j<n;j++){
if(s[j]=='#') mp[i][j+1]=true;
else mp[i][j+1]=false;
}
}
/* for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d",mp[i][j]);
}
puts("");
}*/
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(!mp[i][j]) continue;
for(int k=0;k<4;k++){
int nx=i+to[k][0]; int ny=j+to[k][1];
if(mp[nx][ny])
addedge((i-1)*n+j,(nx-1)*n+ny);
// mp[nx][ny]=false ;
}
}
}
printf("Case %d: %d\n",zz++,solve(n)/2); // 重复
}
return 0;
}
/*
2
6
......
.##...
......
.#..#.
.#..##
......
4
###.
#...
.###
..#.
*/
B道路建设
分析:最小生成树模板题
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 1e5 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
return x*f;
}
/*----------------------------------*/
struct Edge{
int from,to,val;
}edge[M];
bool cmp(Edge a,Edge b){
return a.val<b.val;
}
int pre[N];
void init(int n){
for(int i=0;i<=n;i++) pre[i]=i;
}
int Find(int x){
return x==pre[x]?x:(pre[x]=Find(pre[x]));
}
void Join(int x,int y){
x=Find(x);y=Find(y);
if(x!=y) pre[x]=y;
}
int main(){
int c,n,m;
while(scanf("%d%d%d",&c,&n,&m)!=EOF){
init(m);
for(int i=0;i<n;i++)
scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].val);
sort(edge,edge+n,cmp);
int ans=0; int flag=1;
for(int i=0;i<n;i++){
Edge e=edge[i];
if(Find(e.to)!=Find(e.from)){
Join(e.to,e.from);
ans+=e.val;
}
}
if(ans<=c) puts("Yes") ;
else puts("No");
}
return 0;
}
/*
链接:https://www.nowcoder.net/acm/contest/76/B
来源:牛客网
20 10 5
1 2 6
1 3 3
1 4 4
1 5 5
2 3 7
2 4 7
2 5 8
3 4 6
3 5 9
4 5 2
10 2 2
1 2 5
1 2 15
*/
C求交集
分析:二分查找。
我用map MLE了..QAQ
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 2e6 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
return x*f;
}
/*----------------------------------*/
int a[N];
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=0;i<n;i++) scanf("%d",&a[i]);
int have=0;
for(int i=0;i<m;i++){
int c;scanf("%d",&c);
int pos=lower_bound(a,a+n,c)-a;
if(a[pos]==c) {
if(have++) putchar(' ');
printf("%d",c);
}
}
if(!have) puts("empty");
else puts("");
}
return 0;
}
D 小明的挖矿之旅
分析: 因为每个点只能够右和下移动,所以整个图就相当于一个DAG图。然后讨论入度为0 和出度为0的个数就行了
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 1000*1000 +11;
const int M = 1000+11;
const int inf = 0x3f3f3f3f;
const LL inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
return x*f;
}
/*----------------------------------*/
//vector<int>ve[N];
int in[N],out[N];
void init(int n){
for(int i=0;i<n;i++) {
// ve[i].clear();
out[i]=in[i]=0;
}
}
void addedge(int a,int b){
// ve[a].push_back(b);
in[b]++; out[a]++;
}
bool mp[M][M];
void show(int n,int m){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
printf("%d",mp[i][j]);
}
puts("");
}
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF){
init(n*m);memset(mp,0,sizeof(mp));
for(int i=0;i<n;i++){
string s;cin>>s;
for(int j=0;j<m;j++){
if(s[j]=='.') mp[i+1][j+1]=true;
else mp[i+1][j+1]=false;
}
}
// show(n,m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]){
int nx=i+1;int ny=j;
if(mp[nx][ny]) addedge((i-1)*m+j-1,(nx-1)*m+ny-1);
nx=i;ny=j+1;
if(mp[nx][ny]) addedge((i-1)*m+j-1,(nx-1)*m+ny-1);
}
}
}
int a,b,c;
a=b=c=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]){
if(in[(i-1)*m+j-1]==0) a++;
if(out[(i-1)*m+j-1]==0) b++;
c++;
}
}
}
if(c==0) puts("0");
else if(a==c&&b==c) printf("%d\n",a-1);
else printf("%d\n",max(a,b));
}
return 0;
}
E 通知小弟
分析:scc+缩点 ,求缩点后的入度 ,如果入度为0且HA能够通知到的间谍 不在这个缩点里的话,肯定是-1 ,否则就是入度为0的点的个数。
只要入度为0的被通知了,那么入度不为的点肯定会由入度为0的传过来。
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 1000 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
return x*f;
}
/*----------------------------------*/
struct Edge{
int from,to,nexts;
}edge[M];
int head[N],top;
int n,m;
void init(){
memset(head,-1,sizeof(head)) ;
top=0;
}
void addedge(int a,int b){
Edge e={a,b,head[a]} ;
edge[top]=e;head[a]=top++;
}
int dfn[N],low[N];
int sccno[N],scc_cnt;
stack<int>S; bool Instack[N];
vector<int>scc[N];
int mp[N][N];
int dfs_clock;
void tarjan(int now){
low[now]=dfn[now]=++dfs_clock;
S.push(now);Instack[now]=1;
for(int i=head[now];i!=-1;i=edge[i].nexts){
Edge e=edge[i];
if(!dfn[e.to]){
tarjan(e.to);
low[now]=min(low[now],low[e.to]);
}else if(Instack[e.to])
low[now]=min(low[now],dfn[e.to]);
}
if(dfn[now]==low[now]){
scc_cnt++;scc[scc_cnt].clear();
for(;;){
int nexts=S.top();S.pop();Instack[nexts]=0;
sccno[nexts]=scc_cnt;
scc[scc_cnt].push_back(nexts);
if(nexts==now) break;
}
}
}
void find_cut(int le,int ri){
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(Instack,0,sizeof(Instack));
memset(sccno,0,sizeof(sccno));
dfs_clock=scc_cnt=0;
for(int i=le;i<=ri;i++)
if(!dfn[i]) tarjan(i);
}
int in[N];
void suodian(){ // 建立DAG图
for(int i=1;i<=scc_cnt;i++)
memset(mp[i],0,sizeof(mp[i]));
for(int i=1;i<=scc_cnt;i++) in[i]=0;
for(int i=0;i<top;i++){
Edge e=edge[i];
int now=sccno[e.from];
int nexts=sccno[e.to];
if(now!=nexts){
in[nexts]++;
mp[now][nexts]=1;
}
}
}
int HA[N];
map<int,int>zzx;
int main(){
int mm;
while(scanf("%d%d",&n,&mm)!=EOF){
init(); zzx.clear();
for(int i=1;i<=mm;i++) scanf("%d",&HA[i]);
for(int i=1;i<=n;i++){
int num=0; scanf("%d",&num);
for(int j=1;j<=num;j++){
int zz; scanf("%d",&zz);
addedge(i,zz);
}
}
find_cut(1,n);
suodian();
//cout<<scc_cnt<<endl;
for(int i=1;i<=mm;i++) zzx[sccno[HA[i]]]=1;
int flag=1; int ans=0;
for(int i=1;i<=scc_cnt;i++){
if(in[i]==0){
if(zzx[i]==0) flag=0; // HA通知到的间谍有没有这个在这里联通快中
ans++;
}
}
if(!flag) puts("-1");
else printf("%d\n",ans);
}
return 0;
}
F Call to your teacher
分析:floyd 求传递闭包 模板题
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 100 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
return x*f;
}
/*----------------------------------*/
int mp[N][N];
int n,m;
void wall(){
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++){
mp[i][j]=mp[i][j]|(mp[i][k]&mp[k][j]);
}
}
}
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
memset(mp,0,sizeof(mp));
while(m--){
int a,b;scanf("%d%d",&a,&b);
mp[a][b]=1;
}
wall();
if(mp[1][n]) puts("Yes");
else puts("No");
}
return 0;
}
G 老子的意大利炮呢
分析: 状态压缩 + 优先队列的BFS
不难,但是太菜了,没时间写了。
三种物品,可以用状态压缩来表示当前拥有的状态 。
1<<1 表示拥有第一件物品,1<<2表示拥有第二件物品 ,1<<3表示拥有第三件物品.
然后 就是针对每种情况逐个分析就行了 ,这里一定要思路清晰,不然很容易错。
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 100+11;
const int M = 1E6+11;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const LL inff = 0x3f3f3f3f3f3f3f3f;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1; ch=getchar();}
while(ch<='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
/*-------------------------*/
struct Node {
int x,y,step,state;
bool operator<(const Node &b)const {
return step>b.step;
}
};
int mp[N][N],speed[1<<5];
int vis[N][N][1<<5];
int to[4][2]={1,0,0,1,-1,0,0,-1};
void Cal(int &cnt,int &tt,Node now){
cnt=0; tt=1;
for(int i=1;i<=3;i++){
if((1<<i)&now.state){
cnt++; tt+=speed[1<<i];
}
}
}
void bfs(Node st){
memset(vis,0,sizeof(vis));
priority_queue<Node>Q;
Q.push(st); vis[st.x][st.y][st.state]=1;
while(!Q.empty()){
Node now=Q.top(); Q.pop();
for(int i=0;i<4;i++){
int nx=now.x+to[i][1]; int ny=now.y+to[i][0];
if(mp[nx][ny]==0 || vis[nx][ny][now.state]) continue; //对所有的情况逐个分析 关键
if(mp[nx][ny]==6){
int cnt,tt; Cal(cnt,tt,now);
if(cnt!=3){
Node next={nx,ny,now.step+tt,now.state};
vis[nx][ny][next.state]=1;
Q.push(next);
}
continue;
}
if(mp[nx][ny]==5){
int cnt,tt; Cal(cnt,tt,now);
if(cnt==3) {
//printf("%d \n",tt);
printf("%d\n",now.step+tt);
return ;
}
continue;
}
if(mp[nx][ny]==1) {
int cnt,tt; Cal(cnt,tt,now);
Node ne={nx,ny,now.step+tt,now.state};
vis[nx][ny][ne.state]=1; Q.push(ne);
continue;
}
if(mp[nx][ny]>=2&&mp[nx][ny]<=4){
int cnt,tt; Cal(cnt,tt,now);
Node ne={nx,ny,now.step+tt,now.state | (1<<(mp[nx][ny]-1))};
vis[nx][ny][ne.state]=1; Q.push(ne);
Node next={nx,ny,now.step+tt,now.state};
vis[nx][ny][next.state]=1; Q.push(next);
continue;
}
}
}
puts("-1");
}
void show(int n,int m){ //debug
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++) {
printf("%d",mp[i][j]);
}
puts("");
}
}
int main(){
memset(mp,0,sizeof(mp));
int n,m; scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
string s;cin>>s;
for(int j=0;j<m;j++){
if(s[j]=='#') mp[i][j+1]=6;
else mp[i][j+1]=1;
}
}
Node st;
for(int i=1;i<=5;i++){
int x,y;scanf("%d%d",&x,&y);
if(i==1) { st.x=x;st.y=y;st.step=0;st.state=0; }
mp[x][y]=i;
}
// show(n,m);
speed[0]=1;
for(int i=1;i<=3;i++){
int t;scanf("%d",&t);
speed[1<<i]=t;
}
// for(int i=1;i<=3;i++) printf("%d ",speed[1<<i]);
bfs(st);
return 0;
}
/*
3 5
##.##
.#.#.
##.##
1 3 2 1 2 3 2 5 3 3
1 5 4
*/
H 老子的全排列呢
分析:直接调用函数 。
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
const int N = 500 +11;
const int M = 1e6+11;
const int inf = 0x3f3f3f3f;
const LL inff= 0x3f3f3f3f3f3f3f3f ;
const int mod = 1e9+7;
const double PI = acos(-1.0);
int read(){
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=(x<<1)+ (x<<3)+ch-'0' ; ch=getchar();}
return x*f;
}
/*----------------------------------*/
int a[8]={1,2,3,4,5,6,7,8};
int main(){
do{
for(int i=0;i<8;i++) printf("%d%s",a[i],i==7?"":" ");
puts("");
}while(next_permutation(a,a+8));
return 0;
}