西电10.9校内赛补题

 C.

http://www.cnblogs.com/elpsycongroo/p/7643771.html

D.UVa12880

解题关键:dfs,判断每个人是否愿意被其他人交换,注意保证每个人只能被交换一次。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<iostream>
 7 #define maxn 220000
 8 using namespace std;
 9 typedef long long ll;
10 struct Edge{
11     int nxt;
12     int to;
13 }e[maxn];
14 int head[maxn],cnt,pre[maxn];
15 bool vis[maxn];
16 void add_edge(int u,int v){//单向
17     e[cnt].to=v;
18     e[cnt].nxt=head[u];
19     head[u]=cnt++;
20 }
21 bool dfs(int u){
22     for(int i=head[u];i!=-1;i=e[i].nxt){
23         int v=e[i].to;
24         if(vis[v]) continue;
25         vis[v]=true;
26         if(pre[v]==-1||dfs(pre[v])){
27             pre[v]=u;
28             return true;
29         }
30     }
31     return false;
32 }
33 int main(){
34     int n,m,a,b;
35     while(scanf("%d%d",&n,&m)!=EOF){
36         memset(head, -1, sizeof head);
37         memset(pre,-1,sizeof pre);
38         cnt=0;
39         for(int i=0;i<m;i++){
40             scanf("%d%d",&a,&b);
41             add_edge(a,b);
42         }
43         for(int i=0;i<n;i++){
44             memset(vis,0,sizeof vis);
45             dfs(i);
46         }
47         bool flag=false;
48         for(int i=0;i<n;i++){
49             if(pre[i]==-1){
50                 flag=true;
51                 break;
52             }
53         }
54         if(flag) printf("NO\n");
55         else printf("YES\n");
56     }
57     return 0;
58 }
View Code

E.hdu4313

解题关键:正向的思路是将边从小到大排序,如果去掉某条边,两个特殊点并起来了,则需去掉该边,我们反向考虑,将边从大到小排序,依次向图中加边,如果两个点并起来了,则需去掉该边。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<vector>
 7 #include<cmath>
 8 #define maxn 100020
 9 using namespace std;
10 typedef long long ll;
11 int par[maxn],n,k;
12 //bool vis[maxn];
13 struct edge{
14     int u;
15     int v;
16     int w;
17 }e[maxn];
18 bool flag[maxn];
19 bool cmp(const edge &a,const edge &b){
20     return a.w>b.w;
21 }
22 void init1(){
23     for(int i=0;i<=n;i++) par[i]=i;
24 }
25 
26 int find1(int x){
27     if(par[x]==x) return x;
28     else return par[x]=find1(par[x]);
29 }
30 
31 void unite(int x,int y){
32     par[x]=y;
33 }
34 
35 int main(){
36     int t,a;
37     ios::sync_with_stdio(0);
38     cin>>t;
39     while(t--){
40         memset(flag, 0, sizeof flag);
41         cin>>n>>k;
42         init1();
43         for(int i=0;i<n-1;i++){
44             cin>>e[i].u>>e[i].v>>e[i].w;
45         }
46         sort(e,e+n-1,cmp);
47         for(int i=0;i<k;i++){
48             cin>>a;
49             flag[a]=1;
50         }
51         ll ans=0;
52         for(int i=0;i<n-1;i++){
53             if(flag[find1(e[i].u)]&&flag[find1(e[i].v)]){
54                 ans+=e[i].w;
55             }
56             else if(flag[find1(e[i].u)]){
57                 unite(find1(e[i].v),find1(e[i].u));
58             }else{
59                 unite(find1(e[i].u), find1(e[i].v));
60             }
61         }
62         cout<<ans<<"\n";
63     }
64     return 0;
65 }
View Code

 F.hdu4324

解题关键:

求是否存在三元环 
如果存在环,则一定存在三元环 (scc和拓扑排序均可)
证明如下: 
不存在二元环 
设存在 $n(n>=3)$元环 $p_1->p_2->p_3->…->p_n->p_1$ 
1) 若存在边 $p_3->p_1$,则存在三元环 $(p_1->p_2->p_3->p_1)$ 
2) 若不存在 $p_3->p_1$,则必然存在 $p_1->p_3$ 
那么 $p_1->p_3->…->p_n->p_1$又构成 $n-1$元环 
递归证明可得,如果存在环,必然存在三元环。

1、targinSCC

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cstdlib>
 5 #include<cmath>
 6 #include<algorithm>
 7 using namespace std;
 8 typedef long long ll;
 9 #define MAXN 2010
10 #define MAXM 4000020
11 struct edge{
12     int to,nxt;
13 }e[MAXM];
14 //int being[MAXN];
15 int head[MAXN],st[MAXN],dfn[MAXN],lowest[MAXN],belong[MAXN];
16 bool inst[MAXN];
17 int t,n,m,scnt,top,tot;//scnt从1开始
18 void init(){
19     memset(head,-1,sizeof head);
20     memset(dfn,0,sizeof dfn);//记住初始化
21   //  memset(being, 0, sizeof being);
22     scnt=top=tot=0;
23 }
24 
25 void add_edge(int u, int v){
26     e[tot].to=v;
27     e[tot].nxt=head[u];
28     head[u]=tot++;
29 }
30 
31 void Tarjan(int u){
32     dfn[u]=lowest[u]=++tot;
33     inst[u]=1;
34     st[top++]=u;
35     for(int i=head[u];i!=-1;i=e[i].nxt){
36         int v=e[i].to;
37         if(!dfn[v]){
38             Tarjan(v);
39             lowest[u]=min(lowest[u],lowest[v]);
40         }
41         else if(inst[v]){
42             lowest[u]=min(lowest[u],dfn[v]);//也可用lowest
43         }
44     }
45     if(dfn[u]==lowest[u]){
46         scnt++;
47         int t;
48         do{
49             t=st[--top];
50             inst[t]=false;
51             belong[t]=scnt;
52         }while(t!=u);
53     }
54 }
55 
56 void solve(){//缩点
57     for(int i=1;i<=n;i++)  if(!dfn[i])  Tarjan(i);
58    /* for(int i=1;i<=n;i++){
59         being[belong[i]]++;
60     }
61     bool flag=false;
62     for(int i=1;i<=scnt;i++){
63         if(being[i]>1){
64             flag=true;
65             break;
66         }
67     }
68     */
69     if(scnt!=n) printf("Yes\n");
70     //if(flag) printf("Yes\n");
71     else printf("No\n");
72 }
73 char ch[2200];
74 int main(){
75     scanf("%d",&t);
76     for(int i=1;i<=t;i++){
77         init();
78         printf("Case #%d: ",i);
79         scanf("%d",&n);
80         for(int j=1;j<=n;j++){
81             scanf("%s",ch);
82             for(int k=0;k<n;k++){
83                 if(ch[k]=='1') add_edge(j,k+1);
84             }
85         }
86         solve();
87     }
88     return 0;
89 }
View Code

 2、toposort

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<cmath>
 7 #include<vector>
 8 #include<queue>
 9 using namespace std;
10 typedef long long ll;
11 const int N=4000200;
12 priority_queue<int,vector<int>,greater<int> >q;//因为是按字典序的,要注意重边的情况
13 int deg[2002],seq[2002];
14 int n,m,u,v,tol,t;
15 struct Edge{
16     int nxt;
17     int to;
18     int w;
19 }e[N];
20 int head[N],cnt;
21 void add_edge(int u,int v){
22     e[cnt].to=v;
23     e[cnt].nxt=head[u];
24     head[u]=cnt++;
25 }
26 bool toposort(){
27     for(int i=1;i<=n;i++)if(!deg[i])q.push(i);
28     tol=0;
29     while(q.size()){
30         int u=q.top();
31         q.pop();
32         seq[tol++]=u;
33         for(int i=head[u];i!=-1;i=e[i].nxt){
34             int v=e[i].to;
35             deg[v]--;
36             if(!deg[v]) q.push(v);
37         }
38     }
39     if(tol==n) return false;
40     else return true;
41 }
42 char ch[2002];
43 int main(){
44     scanf("%d",&t);
45     for(int i=1;i<=t;i++){
46         memset(head, -1, sizeof head);
47         memset(deg, 0, sizeof deg);
48         cnt=0;
49         scanf("%d",&n);
50         for(int j=1;j<=n;j++){
51             scanf("%s",ch);
52             for(int k=0;k<n;k++){
53                 if(ch[k]=='1') add_edge(j,k+1),deg[k+1]++;
54             }
55         }
56         bool flag=toposort();
57         printf("Case #%d: ",i);
58         if(flag) printf("Yes\n");
59         else printf("No\n");
60     }
61     return 0;
62 }
View Code

 

G.hdu4318

解题关键:最短路转化为最长路。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<cmath>
 7 #include<queue>
 8 using namespace std;
 9 const int maxn=50002;
10 const int maxm=2600010;
11 int head[maxn],tot,n,m;
12 struct edge{
13     int to;
14     double w;
15     int nxt;
16 }e[maxm];
17 void add_edge(int u,int v,double w){
18     e[tot].w=w;
19     e[tot].to=v;
20     e[tot].nxt=head[u];
21     head[u]=tot++;
22 }
23 bool vis[maxn];
24 queue<int>que;//队列是点的队列
25 double d[maxn];
26 void spfa(int s){
27     for(int i=0;i<=n;i++) d[i]=0.0;
28     memset(vis,0,sizeof vis);
29     while (!que.empty()) que.pop();
30     que.push(s);
31     vis[s]=true;
32     d[s]=1.0;
33     while (!que.empty()){
34         int u=que.front();
35         que.pop();
36         vis[u]=false;
37         for (int i=head[u];i!=-1;i=e[i].nxt){
38             int v=e[i].to;
39             double w=e[i].w;
40             if (d[v]<d[u]*w){
41                 d[v]=d[u]*w;
42                 if (!vis[v]){
43                     vis[v]=true;
44                     que.push(v);//hash一下,可判断是否存在负环
45                 }
46             }
47         }
48     }
49 }
50 int main(){
51     int a,b,k,td;
52     //double c;
53     while(scanf("%d",&n)!=EOF){
54         memset(head, -1, sizeof head);
55         tot=0;
56         for(int i=0;i<n;i++){
57             scanf("%d",&k);
58             for(int j=0;j<k;j++){
59                 scanf("%d%d",&b,&td);
60                 add_edge(i+1,b,1-td*0.01);
61             }
62         }
63         scanf("%d%d%d",&a,&b,&td);
64         spfa(a);
65         if(d[b]==0){
66             printf("IMPOSSIBLE!\n");
67         }else{
68             printf("%.2f\n",td-td*d[b]);
69         }
70     }
71     return 0;
72 }
View Code

 

H.hdu4302

解题关键:优先队列分别维护左右距离x最近的点,然后模拟即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 priority_queue<int>q1;
 5 priority_queue<int,vector<int>,greater<int> >q2;
 6 int main(){
 7     int t,l,n,a,b,now,x,m,ans;
 8     scanf("%d",&t);
 9     for(int ca=1;ca<=t;ca++){
10         x=0;
11         scanf("%d%d",&n,&m);
12         while(!q1.empty()) q1.pop();
13         while(!q2.empty()) q2.pop();
14         ans=0;
15         for(int i=0;i<m;i++){
16             scanf("%d",&a);
17             if(a==1){
18                 if(!q1.empty()&&!q2.empty()){
19                     int t1=x-q1.top();
20                     int t2=q2.top()-x;
21                     if(t1<t2){
22                         x=q1.top();
23                         now=-1;
24                         ans+=t1;
25                         q1.pop();
26                     }
27                     else if(t1>t2){
28                         x=q2.top();
29                         now=1;
30                         q2.pop();
31                         ans+=t2;
32                     }
33                     else if(now==1){
34                         x=q2.top();
35                         now=1;
36                         q2.pop();
37                         ans+=t2;
38                     }else{
39                         x=q1.top();
40                         now=-1;
41                         q1.pop();
42                         ans+=t1;
43                     }
44                 }
45                 else if(!q1.empty()){
46                     int t1=x-q1.top();
47                     now=-1;
48                     x=q1.top();
49                     ans+=t1;
50                     q1.pop();
51                 }
52                 else if(!q2.empty()){
53                     int t2=q2.top()-x;
54                     now=1;
55                     x=q2.top();
56                     q2.pop();
57                     ans+=t2;
58                 }
59             }else{
60                 scanf("%d",&b);
61                 if(b>x){
62                     q2.push(b);
63                 }else{
64                     q1.push(b);
65                 }
66             }
67         }
68         printf("Case %d: %d\n",ca,ans);
69     }
70 } 
View Code

 

I.hdu4308

解题关键:bfs简单裸题,考验手速和细节。

 1 #include<bits/stdc++.h>
 2 #define inf 0x3f3f3f3f
 3 using namespace std;
 4 typedef long long ll;
 5 char arr[5002][5002];
 6 int r,c,cost,sx,sy,tx,ty;
 7 struct node{
 8     int x,y;
 9 };
10 int d[5002][5002];
11 const int dx[4]={1,0,-1,0};
12 const int dy[4]={0,1,0,-1};
13 node q1[5002];int rear;
14 int bfs(node st){
15     for(int i=0;i<r;i++) for(int j=0;j<c;j++) d[i][j]=inf;
16     queue<node>q;
17     q.push(st);
18     d[st.x][st.y]=0;
19     while(q.size()){
20         node p=q.front();
21         q.pop();
22         //if(p.x==tx&&p.y==ty) return d[p.x][p.y];
23         for(int i=0;i<4;i++){
24             int nx=p.x+dx[i],ny=p.y+dy[i];
25             if(nx<0||nx>=r||ny<0||ny>=c||arr[nx][ny]=='#'||d[nx][ny]!=inf) continue;
26             if(arr[nx][ny]=='*'){
27                 q.push((node){nx,ny});
28                 d[nx][ny]=d[p.x][p.y]+1;
29             }else if(arr[nx][ny]=='P'){
30                 d[nx][ny]=d[p.x][p.y];
31                 for(int i=0;i<rear;i++){
32                     int tmpx=q1[i].x,tmpy=q1[i].y;
33                     d[tmpx][tmpy]=d[nx][ny];
34                     q.push((node){tmpx,tmpy});
35                 }
36             }else if(arr[nx][ny]=='C'){
37                 d[nx][ny]=d[p.x][p.y];
38                 return d[nx][ny];
39             }
40         }
41     }
42     return -1;
43 }
44 int main(){
45     while(scanf("%d%d%d",&r,&c,&cost)!=EOF){
46         rear=0;
47         for(int i=0;i<r;i++) scanf("%s",arr+i);
48         for(int i=0;i<r;i++) for(int j=0;j<c;j++){
49              if(arr[i][j]=='Y') sx=i,sy=j;
50             if(arr[i][j]=='C') tx=i,ty=j; 
51             if(arr[i][j]=='P'){
52                 q1[rear++]=(node){i,j};
53             }
54         }
55         int ans=bfs((node){sx,sy});
56         if(ans==-1) printf("Damn teoy!\n");
57         else printf("%d\n",ans*cost);
58     }
59     return 0;
60 } 
View Code

 

J.UVa1521

解题关键:贪心,会得出猜的数是1时需要的步数最大,然后就是将n以内的质数全部筛出,转化为质数分组的问题,然后双指针解决即可。

每次询问,相当于确定每个质数P是否出现。考虑到最坏情况,一定是问什么都回答1,否则的话就相当于把$n$缩小成了$\frac{n}{p}$。

问题就转换成了将1~n中间的质数分成K组,每组内的质数之积不大于$n$,求最小的$k$。

对于不小于$\sqrt{n}$的质数来说,他一定只能和小于$\sqrt{n}$的质数来配对,这样答案至少为不小于$\sqrt{n}$的质数个数。

而小于$\sqrt{n}$的质数的个数一定比不小于$\sqrt{n}$的质数的个数小很多,并且一定可以找到一个质数来配对。

所以问题的答案可以通过贪心来求,递减枚举每一个不小于质数,判断当前最小质数是否可以合并。

1、考虑乘法,小的因子每增大1,大的因子势必会减小很多,利用这个性质,可以得到,每个小的因子只能和一个大的因子合并。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int MAXN=30001;
 5 int prime[MAXN];//保存素数
 6 bool vis[MAXN];//初始化
 7 int LSsieve(int n){
 8     int cnt=0;
 9     memset(vis,0,sizeof vis);
10     for(int i=2;i<n;i++){
11         if(!vis[i]) prime[cnt++]=i;
12         for(int j=0;j<cnt&&i*prime[j]<n;j++){
13             vis[i*prime[j]]=1;
14             if(i%prime[j]==0)   break;
15         }
16     }
17     return cnt;//返回小于n的素数的个数 
18 }
19 
20 
21 int main(){
22     int n;
23     int cnt=LSsieve(10001);
24     while(scanf("%d",&n)!=EOF){
25         int i=0,j=cnt-1,ans=0;
26         while(prime[j]>n) j--;
27         while(i<=j){
28             ans++;
29             if(prime[i]*prime[j]<=n) i++,j--;
30             else j--; 
31         }
32         printf("%d\n",ans);
33     }
34 
35     return 0;
36 } 
View Code

 2、暴力分组。先取最大,然后用小的填充。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<iostream>
 6 #include<cmath>
 7 using namespace std;
 8 typedef long long ll;
 9 const int MAXN=30001;
10 int prime[MAXN];//保存素数
11 bool vis[MAXN];//初始化
12 int LSsieve(int n){
13     int cnt=0;
14     memset(vis,0,sizeof vis);
15     for(int i=2;i<n;i++){
16         if(!vis[i]) prime[cnt++]=i;
17         for(int j=0;j<cnt&&i*prime[j]<n;j++){
18             vis[i*prime[j]]=1;
19             if(i%prime[j]==0)  break;
20         }
21     }
22     return cnt;//返回小于n的素数的个数
23 }
24 
25 
26 int main(){
27     int n;
28     int cnt=LSsieve(10001);
29     while(scanf("%d",&n)!=EOF){
30         int i=0,j=cnt-1,ans=0,now;
31         while(prime[j]>n) j--;
32         while(i<=j){
33             now=prime[j];
34             while(prime[i]*now<=n) now*=prime[i],i++;
35             j--;
36             ans++;
37         }
38         printf("%d\n",ans);
39     }
40     return 0;
41 }
View Code

 

posted @ 2017-10-11 01:30  Elpsywk  阅读(252)  评论(0编辑  收藏  举报