https://www.luogu.org/problem/show?pid=3386
二分图模版题……debug真累
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1001;
int n,m,e;
bool vis[maxn],a[maxn][maxn]={0};//u,v
int shu[maxn]={0};//判断m中点与n中何点连接
bool dfs(int i){
for(int j=1;j<=m;j++){
if(a[i][j]&&!vis[j]){
vis[j]=1;
if(!shu[j]||dfs(shu[j])){
shu[j]=i;
return 1;
}
}
}
return 0;
}
int main(){
int u,v,ans=0;
scanf("%d%d%d",&n,&m,&e);
for(int i=1;i<=e;i++){
scanf("%d%d",&u,&v);
if(u>n||v>m) continue;
a[u][v]=1;
}
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(dfs(i))ans++;
}
printf("%d",ans);
return 0;
}
顺便攒一道题
hdu 3036
未完成
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=10000;
const int INF=2147483640;
struct{
int next;
int to;
int w;
}edge[1000000];
int head[maxn],cnt=-1;
void add(int u,int v,int w){//u起点v终点w容量
cnt++;
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
int lev[maxn],cur[maxn];//lev层数,cur[i]为以i为起点的边的编号
bool bfs(int m){//强制1为源点,m为汇点
int dui[m],r=0;//队列和右指针
for(int i=1;i<=m;i++){//初始化
lev[i]=-1;
cur[i]=head[i];
}
dui[0]=1,lev[1]=0;
int u,v;//u起点v终点
for(int l=0;l<=r;l++){//左指针
u=dui[l];
for(int e=head[u];e!=-1;e=edge[e].next){
v=edge[e].to;
if(edge[e].w>0&&lev[v]==-1){//1.能走 2.未分层
lev[v]=lev[u]+1;
r++;
dui[r]=v;//v入队
if(v==m)return 1;//分层完毕
}
}
}
return 0;//无法分层
}
int dinic(int u,int flow,int m){//u当前点,flow为下面的点能够分配多大的流量,m终点
if(u==m)return flow;//终点直接全流入
int res=0,delta;//res实际流量
for(int &e=cur[u];e!=-1;e=edge[e].next){//'&'相当于cur[u]=e;即流满的边不会再被扫一次
int v=edge[e].to;
if(edge[e].w>0&&lev[u]<lev[v]){//只能从低层往高层流
delta=dinic(v,min(edge[e].w,flow-res),m);
if(delta>0){//如果增广
edge[e].w-=delta;//正向边容量减少
edge[e^1].w+=delta;//反向边仍量增加(暗示退流)
res+=delta;//扩张流量增加
if(res==flow)break;//可流的都流完了,及时跳出
}
}
}
if(res!=flow)lev[u]=-1;//没流完,说明以后不能从这个点流出任何流量,那就不需要这个点了
return res;
}
char a[14][14];
int vis[14][14],dis[14][14];
void BFS(int x,int y){
int x1[160],y1[160];
int r=0;
x1[0]=x;y1[0]=y;dis[x][y]=0;
for(int l=0;l<=r;l++){
int t1=x1[l],t2=y1[l];
if(a[t1+1][t2]!='X'&&vis[t1+1][t2]==0){
r++;
x1[r]=t1+1;y1[r]=t2;
vis[t1+1][t2]=1;
dis[t1+1][t2]=min(dis[t1+1][t2],dis[t1][t2]+1);
}
if(a[t1-1][t2]!='X'&&vis[t1-1][t2]==0){
r++;
x1[r]=t1-1;y1[r]=t2;
vis[t1-1][t2]=1;
dis[t1-1][t2]=min(dis[t1-1][t2],dis[t1][t2]+1);
}
if(a[t1][t2+1]!='X'&&vis[t1][t2+1]==0){
r++;
x1[r]=t1;y1[r]=t2+1;
vis[t1][t2+1]=1;
dis[t1][t2+1]=min(dis[t1][t2+1],dis[t1][t2]+1);
}
if(a[t1][t2-1]!='X'&&vis[t1][t2-1]==0){
r++;
x1[r]=t1;y1[r]=t2-1;
vis[t1][t2-1]=1;
dis[t1][t2-1]=min(dis[t1][t2-1],dis[t1][t2]+1);
}
}
return;
}
int id[14][14];
int rdis[14][14][144]={0};
int main(){
int r,c,t;
int sumH=0,sumE=0;
scanf("%d%d%d\n",&r,&c,&t);
for(int i=1;i<=r;i++){
for(int j=1;j<=c+1;j++){
scanf("%c",a[i][j]);
if(a[i][j]=='.'){
sumH++;
id[i][j]=sumH;
}
if(a[i][j]=='E'){
sumE++;
id[i][j]=sumE;
}
}
}
for(int i=1;i<=r;i++){
a[i][0]='X';a[i][c+1]='X';
}
for(int j=1;j<=c;j++){
a[0][j]='X';a[r+1][j]='X';
}
for(int i=1;i<=r;i++){
for(int j=1;j<=c;j++){
if(a[i][j]=='E'){
memset(vis,0,sizeof(vis));
for(int k=1;k<=r;k++){
for(int l=1;l<=c;l++){
dis[k][l]=INF-1;
}
}
BFS(i,j);
for(int k=1;k<=r;k++){
for(int l=1;l<=c;l++){
if(a[k][l]=='.'){
rdis[k][l][id[i][j]]=dis[k][l];
}
}
}
}
}
}
for(int i=1;i<=t+sum+2;i++){
head[i]=-1;
}
for(int i=1;i<=n;i++){
int s,e,c;
scanf("%d%d%d",&s,&e,&c);
add(s,e,c);
add(e,s,0);
}
int ans=0;
while(bfs(m)==1)ans+=dinic(1,INF,m);
printf("%d",ans);
return 0;
}
http://codevs.cn/problem/1993/
草地排水,网络流dinic板子
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=201;
const int INF=2147483640;
struct{
int next;
int to;
int w;
}edge[2*maxn];
int head[2*maxn],cnt=-1;
void add(int u,int v,int w){//u起点v终点w容量
cnt++;
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
int lev[maxn],cur[maxn];//lev层数,cur[i]为以i为起点的边的编号
bool bfs(int m){//强制1为源点,m为汇点
int dui[m],r=0;//队列和右指针
for(int i=1;i<=m;i++){//初始化
lev[i]=-1;
cur[i]=head[i];
}
dui[0]=1,lev[1]=0;
int u,v;//u起点v终点
for(int l=0;l<=r;l++){//左指针
u=dui[l];
for(int e=head[u];e!=-1;e=edge[e].next){
v=edge[e].to;
if(edge[e].w>0&&lev[v]==-1){//1.能走 2.未分层
lev[v]=lev[u]+1;
r++;
dui[r]=v;//v入队
if(v==m)return 1;//分层完毕
}
}
}
return 0;//无法分层
}
int dinic(int u,int flow,int m){//u当前点,flow为下面的点能够分配多大的流量,m终点
if(u==m)return flow;//终点直接全流入
int res=0,delta;//res实际流量
for(int &e=cur[u];e!=-1;e=edge[e].next){//'&'相当于cur[u]=e;即流满的边不会再被扫一次
int v=edge[e].to;
if(edge[e].w>0&&lev[u]<lev[v]){//只能从低层往高层流
delta=dinic(v,min(edge[e].w,flow-res),m);
if(delta>0){//如果增广
edge[e].w-=delta;//正向边容量减少
edge[e^1].w+=delta;//反向边仍量增加(暗示退流)
res+=delta;//扩张流量增加
if(res==flow)break;//可流的都流完了,及时跳出
}
}
}
if(res!=flow)lev[u]=-1;//没流完,说明以后不能从这个点流出任何流量,那就不需要这个点了
return res;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
head[i]=-1;
}
for(int i=1;i<=n;i++){
int s,e,c;
scanf("%d%d%d",&s,&e,&c);
add(s,e,c);
add(e,s,0);
}
int ans=0;
while(bfs(m)==1)ans+=dinic(1,INF,m);
printf("%d",ans);
return 0;
}
【题目描述】
给出一张n*n(n<=100)的国际象棋棋盘,其中被删除了一些点,问可以使用多少1*2的多米诺骨牌进行掩盖。
【输入格式】
第一行为n,m(表示有m个删除的格子)
第二行到m+1行为x,y,分别表示删除格子所在的位置
【输出格式】
一个数,即最大覆盖格数
【样例输入】
8 0
【样例输出】
32
想象真的国际象棋棋盘,黑色的一帮,白色的一帮,黑白相邻的那么从黑连向白的,变成二分图匹配。
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=102;
int n,m,e;
bool vis[maxn][maxn],a[maxn][maxn][maxn][maxn]={0};//u,v
int shu[maxn][maxn][2]={0};//判断m中点与n中何点连接
bool dfs(int i,int j){
for(int k=-1;k<=1;k++){
for(int l=-1;l<=1;l++){
if(k==l||k+l==0)continue;
if(i+k==0||j+l==0||i+k==n+1||j+l==n+1)continue;
if(a[i][j][i+k][j+l]&&!vis[i+k][j+l]){
vis[i+k][j+l]=1;
if((!shu[i+k][j+l][0]&&!shu[i+k][j+l][1])||dfs(shu[i+k][j+l][0],shu[i+k][j+l][1])){
shu[i+k][j+l][0]=i;
shu[i+k][j+l][1]=j;
return 1;
}
}
}
}
return 0;
}
int main(){
int u,v,ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i%2==j%2){
a[i][j][i-1][j]=a[i][j][i+1][j]=a[i][j][i][j-1]=a[i][j][i][j+1]=1;
}
}
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
if(x%2==y%2){
a[x][y][x-1][y]=a[x][y][x+1][y]=a[x][y][x][y-1]=a[x][y][x][y+1]=0;
}else{
a[x-1][y][x][y]=a[x+1][y][x][y]=a[x][y-1][x][y]=a[x][y+1][x][y]=0;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
memset(vis,0,sizeof(vis));
if(dfs(i,j))ans++;
}
}
printf("%d",ans);
return 0;
}
codevs1789:最大获利
http://codevs.cn/problem/1789/
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=55010;
const int INF=2147483640;
struct{
int next;
int to;
int w;
}edge[6666666];//随便打的不然maxn的平方会爆空间
int head[maxn],cnt=-1;
void add(int u,int v,int w){//u起点v终点w容量
cnt++;
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
int lev[maxn],cur[maxn];//lev层数,cur[i]为以i为起点的边的编号
bool bfs(int n,int m,int zong){//n为源点,m为汇点,zong为个数
int dui[zong+1],r=0;//队列和右指针
for(int i=1;i<=zong;i++){//初始化
lev[i]=-1;
cur[i]=head[i];
}
dui[0]=n,lev[n]=0;
int u,v;//u起点v终点
for(int l=0;l<=r;l++){//左指针
u=dui[l];
for(int e=head[u];e!=-1;e=edge[e].next){
v=edge[e].to;
if(edge[e].w>0&&lev[v]==-1){//1.能走 2.未分层
lev[v]=lev[u]+1;
r++;
dui[r]=v;//v入队
if(v==m)return 1;//分层完毕
}
}
}
return 0;//无法分层
}
int dinic(int u,int flow,int m){//u当前点,flow为下面的点能够分配多大的流量,m终点
if(u==m)return flow;//终点直接全流入
int res=0,delta;//res实际流量
for(int &e=cur[u];e!=-1;e=edge[e].next){//'&'相当于cur[u]=e;即流满的边不会再被扫一次
int v=edge[e].to;
if(edge[e].w>0&&lev[u]<lev[v]){//只能从低层往高层流
delta=dinic(v,min(edge[e].w,flow-res),m);
if(delta>0){//如果增广
edge[e].w-=delta;//正向边容量减少
edge[e^1].w+=delta;//反向边仍量增加(暗示退流)
res+=delta;//扩张流量增加
if(res==flow)break;//可流的都流完了,及时跳出
}
}
}
if(res!=flow)lev[u]=-1;//没流完,说明以后不能从这个点流出任何流量,那就不需要这个点了
return res;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n+m+2;i++){
head[i]=-1;
}
for(int i=1;i<=n;i++){
int s;
scanf("%d",&s);
add(i,n+m+2,s);
add(n+m+2,i,0);
}
int sum=0;
for(int j=n+1;j<=n+m;j++){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(j,a,INF);add(a,j,0);
add(j,b,INF);add(b,j,0);
add(n+m+1,j,c);add(j,n+m+1,0);
sum+=c;
}
int ans=0;
while(bfs(n+m+1,n+m+2,n+m+2)==1)ans+=dinic(n+m+1,INF,n+m+2);
printf("%d",sum-ans);
return 0;
}
codevs 1163访问艺术馆
http://codevs.cn/problem/1163/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int tree[201][601];
int dis[201][201];
int t;
const int INF=214748364;
int hua[201]={0};
int sum=0;
void read(int fa,int i){
scanf("%d",&dis[fa][i]);
int ha;
scanf("%d",&ha);
if(ha==0){
read(i,i*2);
read(i,i*2+1);
hua[i]=hua[i*2+1]+hua[i*2];
for(int j=0;j<=hua[i];j++){
for(int k=0;k<=j;k++){
int f=0;
if(k!=0)f+=dis[i][i*2]*2;
if(j-k!=0)f+=dis[i][i*2+1]*2;
tree[i][j]=min(tree[i][j],tree[i*2][k]+tree[i*2+1][j-k]+f);
}
}
}else{
hua[i]=ha;
sum+=ha;
for(int j=0;j<=ha;j++){
tree[i][j]=j*5;
}
}
return;
}
int main(){
scanf("%d",&t);
for(int i=0;i<=200;i++){
tree[i][0]=0;
for(int j=1;j<=600;j++){
tree[i][j]=INF;
}
}
read(1,2);
for(int i=sum;i>=0;i--){
if(tree[2][i]+dis[1][2]*2<=t){
printf("%d",i);
return 0;
}
}
return 0;
}
1201: 泥泞的牧场
时间限制: 1 Sec 内存限制: 128 MB
提交: 78 解决: 30
[提交][状态][讨论版]
题目描述
大雨侵袭了奶牛们的牧场.牧场是一个R * C的矩形,其中1≤R,C≤50.大雨将没有长草的土地弄得泥泞不堪,可是小心的奶牛们不想在吃草的时候弄脏她们的蹄子.
为了防止她们的蹄子被弄脏,约翰决定在泥泞的牧场里放置一些木板.每一块木板的宽度为1个单位,长度任意.每一个板必须放置在平行于牧场的泥地里.
约翰想使用最少的木板覆盖所有的泥地.一个木板可以重叠在另一个木板上,但是不能放在草地上.
输入
第1行:两个整数R和C.
第2到R+1行:每行C个字符,其中“*’代表泥地,“.”代表草地.
输出
最少需要多少木板.
样例输入
4 4
..
.*
*.
..*.
样例输出
4
提示
样例说明:
木板的放置方法如下:
1.2.
.333
444.
..2.
木板2和3、4重叠
每个点可以横着板子来与竖着板子来。
那就横着竖着点连一条线,然后要求所有线都能够到
那就是最小点覆盖了+-+
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1000;
int n,m;
char s[maxn][maxn]={0};
int c[maxn][maxn]={0},d[maxn][maxn]={0};
bool vis[maxn],a[maxn][maxn]={0};//u,v
int shu[maxn]={0};//判断m中点与n中何点连接
bool dfs(int i,int o){
for(int j=1;j<=o;j++){
if(a[i][j]&&!vis[j]){
vis[j]=1;
if(!shu[j]||dfs(shu[j],o)){
shu[j]=i;
return 1;
}
}
}
return 0;
}
int main(){
int u,v,ans=0;
int x1=0,y1=0;
scanf("%d%d\n",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m+1;j++){
scanf("%c",&s[i][j]);
if(j==m+1)continue;
if(s[i][j]=='*'){
if(j>1&&s[i][j-1]=='*')c[i][j]=c[i][j-1];
else{
x1++;
c[i][j]=x1;
}
if(i>1&&s[i-1][j]=='*')d[i][j]=d[i-1][j];
else{
y1++;
d[i][j]=y1;
}
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i][j]=='*')
a[c[i][j]][d[i][j]]=1;
}
}
int k=x1;
for(int i=1;i<=k;i++){
memset(vis,0,sizeof(vis));
if(dfs(i,y1))ans++;
}
printf("%d",ans);
return 0;
}
自学KMP
然而
https://www.luogu.org/problem/show?pid=3375
虽然是板子题。
但特别不推荐写。
可能会出现:
1.cincout卡时间
2.gets函数做答案是对的但是就是不给过//深受此毒害的路由器
#include<cstdio>
#include<cstring>
using namespace std;
char s1[1000001];
char s2[1001];
int nxt[1001]={0};
void getnext(int m){//处理nxt数组
//原理:自己匹配自己
int j=0;
for(int i=2;i<=m;i++){
while(j!=0&&s2[j+1]!=s2[i])j=nxt[j];//无法匹配时移动字符串使之能匹配
if(s2[j+1]==s2[i])j++;
nxt[i]=j;//对应匹配的位置(同时也是匹配的长度)
}
return;
}
void KMP(int n,int m){//KMP
int j=0;
for(int i=1;i<=n;i++){
while(j!=0&&s2[j+1]!=s1[i])j=nxt[j];//同上
if(s2[j+1]==s1[i])j++;
if(j==m){//同上
printf("%d\n",i-j+1);
j=nxt[j];//继续查找
}
}
return;
}
int main(){
scanf("%s%s",s1+1,s2+1);
//虽然可以从0开始读入字符串
//但是懒
int n=strlen(s1+1),m=strlen(s2+1);
//相应的字符串长度改一下
getnext(m);
KMP(n,m);
for(int i=1;i<=m;i++){
printf("%d ",nxt[i]);
}
return 0;
}
下面两道是AC自动机模版题
都挺坑的。
十分感谢上面题解的第一位仁兄。
我把他的模版复刻了一遍才过。
另外我才知道用string读字符串要方便。
并且直接用字符串还会更快(这什么原理?!)
总之AC自动机这个黑科技我还没会透。
就这样吧。
https://www.luogu.org/problem/show?pid=3808
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
struct trie{
int ed;
int a[26];
int fail;
}tree[1000000]={0};
int cnt=0;
inline void insert(string s){
int now=0;
int len=s.length();
for(int i=0;i<len;i++){
int t=s[i]-97;
if(tree[now].a[t]==0){
cnt++;
tree[now].a[t]=cnt;
}
now=tree[now].a[t];
}
tree[now].ed++;
return;
}
void getfail(){
queue<int>q;
tree[0].fail=0;
//以下是对第一层的特殊处理
for(int i=0;i<26;i++){
if(tree[0].a[i]!=0){
tree[tree[0].a[i]].fail=0;
q.push(tree[0].a[i]);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<26;i++){
if(tree[u].a[i]!=0){
tree[tree[u].a[i]].fail=tree[tree[u].fail].a[i];
q.push(tree[u].a[i]);
}else{
tree[u].a[i]=tree[tree[u].fail].a[i];
}
}
}
return;
}
int check(string s){
int now=0,ans=0;
int len=s.length();
for(int i=0;i<len;i++){
int t=s[i]-97;
now=tree[now].a[t];
for(int j=now;j&&tree[j].ed!=-1;j=tree[j].fail){
ans+=tree[j].ed;
tree[j].ed=-1;
}
}
return ans;
}
int main(){
int n;
string s;
cin>>n;
for(int i=1;i<=n;i++){
cin>>s;
insert(s);
}
getfail();
cin>>s;
cout<<check(s);
return 0;
}
https://www.luogu.org/problem/show?pid=3796
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
struct trie{
int ed;
int a[26];
int fail;
}tree[100000]={0};
struct remember{
int cont;
int i;
}re[100000]={0};
string s[100000];
bool cmp(remember a,remember b){
if(a.cont!=b.cont)
return a.cont>b.cont;
else
return a.i<b.i;
}
int cnt=0;
inline void insert(string s,int num){
int now=0;
int len=s.length();
for(int i=0;i<len;i++){
int t=s[i]-97;
if(tree[now].a[t]==0){
cnt++;
tree[now].a[t]=cnt;
}
now=tree[now].a[t];
}
tree[now].ed=num;
return;
}
void getfail(){
queue<int>q;
tree[0].fail=0;
//以下是对第一层的特殊处理
for(int i=0;i<26;i++){
if(tree[0].a[i]!=0){
tree[tree[0].a[i]].fail=0;
q.push(tree[0].a[i]);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=0;i<26;i++){
if(tree[u].a[i]!=0){
tree[tree[u].a[i]].fail=tree[tree[u].fail].a[i];
q.push(tree[u].a[i]);
}else{
tree[u].a[i]=tree[tree[u].fail].a[i];
}
}
}
return;
}
void check(string s){
int now=0;
int len=s.length();
for(int i=0;i<len;i++){
int t=s[i]-97;
now=tree[now].a[t];
for(int j=now;j;j=tree[j].fail){
re[tree[j].ed].cont++;
}
}
return;
}
inline void clean(int i){
memset(tree[i].a,0,sizeof(tree[i].a));
tree[i].fail=0;
tree[i].ed=0;
return;
}
int main(){
int n=1;
while(n!=0){
cin>>n;
if(n==0)break;
for(int i=0;i<=cnt;i++){
clean(i);
}
cnt=0;
for(int i=1;i<=n;i++){
cin>>s[i];
re[i].cont=0;
re[i].i=i;
insert(s[i],i);
}
getfail();
cin>>s[0];
check(s[0]);
sort(re+1,re+n+1,cmp);
cout<<re[1].cont<<endl;
cout<<s[re[1].i]<<endl;
for(int i=2;i<=n;++i){
if(re[i].cont==re[i-1].cont){
cout<<s[re[i].i]<<endl;
}
else break;
}
}
return 0;
}
P3366 【模板】最小生成树
https://www.luogu.org/problem/show?pid=3366
//kruskal
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
struct edge{
int u;
int v;
int w;
}e[200001];
bool cmp(edge a,edge b){
return a.w<b.w;
}
int fa[5001]={0};
int find(int a){
if(fa[a]!=a)fa[a]=find(fa[a]);
return fa[a];
}
bool unionn(int a,int b){
int k=find(a);
int p=find(b);
if(k!=p){
fa[p]=k;
return 1;
}
return 0;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
}
sort(e+1,e+1+m,cmp);
int cnt=0,sum=0;
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
if(unionn(e[i].u,e[i].v)){
cnt++;
sum+=e[i].w;
}
if(cnt==n-1)break;
}
int pan=0;
for(int i=1;i<=n;i++)if(fa[i]==i)pan++;
if(pan==1)printf("%d",sum);
else printf("orz");
return 0;
}
寒假考试题
质数
结果碰到了然后重新写了一波
发现这种写法比较好理解
那么存一下把
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
int a[1001];
int on[1001]={0};
int n,m;
int sfk[1001]={0};
int suan=0;
void gredy(int maxn){
if(maxn>m)return;
for(int i=maxn;i<=m;i++){
int ok=0,mie=0;
for(int j=a[i];j<=n;j++){
if(j%a[i]==0){
if(on[j]==1){
mie++;
}
if(on[j]==0){
ok++;
}
}
}
if(ok>mie){
for(int j=a[i];j<=n;j++){
if(j%a[i]==0){
on[j]=1-on[j];
}
}
}
}
return;
}
void dfs(int i,int maxn){
if(i>maxn){
memset(on,0,sizeof(on));
for(int j=1;j<=maxn;j++){
if(sfk[j]==1){
for(int k=a[j];k<=n;k++){
if(k%a[j]==0){
on[k]=1-on[k];
}
}
}
}
gredy(maxn+1);
int ans=0;
for(int i=1;i<=n;i++){
if(on[i]==1)ans++;
}
if(ans>suan){
suan=ans;
}
}else{
for(int j=1;j>=0;j--){
sfk[i]=j;
dfs(i+1,maxn);
}
}
return;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
suan=0;
memset(sfk,0,sizeof(sfk));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+m+1);
int maxn=min(m,11);
dfs(1,maxn);
printf("%d\n",suan);
}
return 0;
}
记一道题
51nod 1459 迷宫游戏
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1459
得等我复习dji才能写了……暴力被卡时了
TLE代码如下
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=501;
const int INF=2147483630;
int sc[maxn];
struct{
int to;
int next;
int w;
}edge[maxn*2];
int cnt=0,head[maxn]={0};
void add(int u,int v,int w){
cnt++;
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt;
return;
}
bool vis[maxn]={0};
int mint=INF,maxw=0;
void dfs(int u,int ed,int t,int sum){
if(u==ed){
if(mint>t){
mint=t;
maxw=sum;
}else if(mint==t){
if(maxw<sum){
maxw=sum;
}
}
return;
}
if(t>mint)return;
vis[u]=1;
for(int i=head[u];i;i=edge[i].next){
int v=edge[i].to;
int w=edge[i].w;
if(vis[v]==0){
dfs(v,ed,t+w,sum+sc[v]);
vis[v]=0;
}
}
return;
}
int main(){
int n,m,st,ed;
scanf("%d%d%d%d",&n,&m,&st,&ed);
for(int i=0;i<n;i++){
scanf("%d",&sc[i]);
}
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dfs(st,ed,0,sc[st]);
printf("%d %d",mint,maxw);
return 0;
}
hdu 5188
一道需要动脑子的01揹包。
于是做一半就去看题解了……gg。
能力还不够啊。
空间最初开小了。
然后就直接看题解的空间开多大就开多大了。
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node{
int t;
int v;
int l;
}a[31];
bool cmp(node b,node c){
if((b.l-b.t)<(c.l-c.t))return 1;
return 0;
}
int f[3000005]={0};//表示时间用量
int main(){
int n;
while(scanf("%d",&n)!=EOF){
memset(f,0,sizeof(f));
int w,ans=0,sum=0,maxn=0;
scanf("%d",&w);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&a[i].t,&a[i].v,&a[i].l);
sum+=a[i].v;//分数总和
ans+=a[i].t;//时间总和
maxn=max(maxn,a[i].l);//最迟交题时间
}
if(w>sum){//分数和不够要求
printf("zhx is naive!\n");
continue;
}
sort(a+1,a+n+1,cmp);
maxn=max(maxn,ans);//与时间总和再比
for(int i=1;i<=n;i++){
for(int j=maxn;j>=a[i].l;j--){//该题可答时间段
if(j>=a[i].t){//该题是否合法
f[j]=max(f[j],f[j-a[i].t]+a[i].v);
}
}
}
bool ok=0;
for(int i=0;i<=maxn;i++){
if(f[i]>=w){
printf("%d\n",i);
ok=1;
break;
}
}
if(ok==0){
printf("zhx is naive!\n");
}
}
return 0;
}