【2019.8.24】

友好的生物

【问题描述】W星球是一个和地球一样气候适宜、物种聚集的星球。经过多年的研究,外星生物学家们已经发现了数万种生物,而且这个数字还在不断增大。W星球上的生物很有趣,有些生物之间很友好,朝夕相伴,形影不离;但有些却很敌对,一见面就难免发生战斗。为了能够更好地了解它们之间的友好程度,外星生物学家希望进行一些量化的计算。他们发现,两种生物之间的友好程度和它们的K种属性有关,暂且将它们编号为属性\(1\)、属性\(2\)、……、属性\(K\),这些属性都是可以进行量化的。外星生物学家研究发现,如果前\(K-1\)种属性的差别越大,这两种生物就越友好;但是属性\(K\)与众不同,这种属性差别越小的两种生物越友好。因此他们猜想是不是可以用这样一个公式量化两种生物之间的友好程度:( 属性i的差别) CK 属性K的差别\(Friendliness=(\sum\limits_{i=1}^{K-1}属性i的差别)-C_K\times属性K的差别\),其中\(C_i\)是非负常数。如果知道了每种生物的各种属性,利用上述公式就很容易算出它们之间的友好程度了。现在,外星生物学家们想问一问:在目前发现的这些生物当中,关最友好的那对生物是哪一对呢?它们之间的友好程度是多少?

【输入文件】输入文件的第一行是两个整数\(N\)\(K\),分别表示目前发现的生物种数和属性的种数。第二行有K个非负整数\(C_i\),即计算友好程度时所需的常数。接下来的\(N\)行,描述每种生物,按照先后顺序依次编号为生物\(1\)、生物\(2\)、……、生物\(N\)。每一行都有K个整数,给出该种生物的各项属性值,按照先后顺序依次编号为属性\(1\)、属性\(2\)、……、属性\(K\)

【输出文件】输出文件包含一行,为一个整数,表示最友好的生物之间的友好程度。

【约定】

\(2 ≤ N ≤ 100,000\) \(2 ≤ K ≤ 5\) \(0 ≤ C_i ≤ 100\)

每种生物的各项属性值不小于\(-10000\)且不大于\(10000\)

最大的友好程度一定大于0

【样例输入】

1 2 3
-5 3 2
-2 3 0
0 5 9
3 4 -1
-10 -11 7

【样例输出】36

【样例说明】生物3和5之间的友好程度为\(1\times|0-(-10)|+2\times|5-(-11)|-3\times|9-7|=36\)

40昏
#include
using namespace std;
const int N=100000+5,M=150000+5,inf=0x3f3f3f3f,P=19650827;
int n,K,a[N][10];
double c[10],ans=0.0;
template void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}
int main(){
	freopen("species.in","r",stdin);
	freopen("species.out","w",stdout);
	rd(n),rd(K);
	for(int i=1;i< = K;++i) scanf("%lf",&c[i]);
	for(int i=1;i< = n;++i)
	for(int j=1;j< = K;++j) rd(a[i][j]);
	for(int i=1;i< = n;++i)
	for(int j=i+1;j< = n;++j){
		double sum=0.0;
		for(int k=1;k < K;++k) sum+=c[k]*Abs(a[i][k]-a[j][k]);
		if(sum < ans) continue;
		sum-=c[K]*Abs(a[i][K]-a[j][K]);
		ans=Max(sum,ans);
	}
	printf("%d",(int)ans);
    return 0;
}
   

正解

\(Friendliness=(\sum\limits_{i=1}^{K-1}属性i的差别)-C_K\times属性K的差别\)\(C_1\times |valx_1-valy_1|+C_2\times |valx_2-valy_2|+...+C_{K-1}\times |valx_{K-1}-valy_{K-1}|-C_K\times |valx_K-valy_K|\)

对于这两个生物中任意一个生物的属性对他俩\(Friendliness\)的贡献就与其拆开绝对值符号之后的正负性有关 因为属性数量$\le$5 就可以枚举每个生物的属性前的符号的情况(\(2^5\))

对于前K-1的情况 就不用担心其将符号枚举反 若\(|a-b|\)拆开为\(a-b\) 其中\(-a+b\)的情况绝对没有\(a-b\)

按第K种属性排序(想一想,为什么) 然后就能得出答案

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
#define Abs(x) ((x)<0?-(x):(x))
const int N=100000+5,M=150000+5,inf=0x3f3f3f3f,P=19650827;
int n,K;
double c[10],ans=0.0;
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

struct node{
	int va;double val[10];
	bool operator <(const node&A)const{return val[K]<A.val[K];}
}a[N];

int main(){
//	freopen("T1.txt","r",stdin);
//	freopen("species.out","w",stdout);
	rd(n),rd(K);
	for(int i=1;i<=K;++i) scanf("%lf",&c[i]);
	for(int i=1;i<=n;++i)
	for(int j=1;j<=K;++j) rd(a[i].va),a[i].val[j]=a[i].va*c[j];
	sort(a+1,a+n+1);
	double nw=0,mn=inf;
	for(int s=0;s<(1<<(K-1));++s,mn=inf){
		for(int i=1;i<=n;++i,nw=0){
			for(int j=1;j<K;++j)
			if(s&(1<<(j-1))) nw+=a[i].val[j];
			else nw-=a[i].val[j];
			nw-=a[i].val[K];
			ans=Max(ans,nw-mn),mn=Min(mn,nw);
		}
	}
	printf("%d",(int)ans);
    return 0;
}

基因重组

\(nwt\)表示当前目标已经拼了多长 \(nws\)表示材料已经用了多长

因为它有可能是这一段正着拼后面一段又进行其它操作 所以一个一个地去做(超级暴力

超级暴力的20昏
using namespace std;
#define ll long long
#define rg register
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
const int N=5000+5,M=1e5+5,inf=0x3f3f3f3f,P=19650827;
int n,m,ans=inf,c1,c2,c3,a[N],b[N];
char s[N],t[N];
template void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}
void dfs(int nwt,int nws,int cos,int cz){
	if(cos>=ans) return;
	if(nwt==m){ans=Min(ans,cos);return;}
	if(nws < n ) {
		if(b[nwt+1]==a[nws+1]){
			if(cz==1) dfs(nwt+1,nws+1,cos,1);
			else dfs(nwt+1,nws+1,cos+c1,1);
		}
		if(b[nwt+1]==(a[nws+1]+(a[nws+1]%2?1:-1))){
			if(cz==3) dfs(nwt+1,nws+1,cos,3);
			else dfs(nwt+1,nws+1,cos+c1,3);
		}
		if(cz==2) dfs(nwt,nws+1,cos,2);
		else dfs(nwt,nws+1,cos+c2,2);	
	}
	dfs(nwt+1,nws,cos+c3,0);
}
int main(){
	freopen("T2.txt","r",stdin);
//	freopen("DNA.out","w",stdout);
	rd(c1),rd(c2),rd(c3);
	scanf("%s",s+1);scanf("%s",t+1);
	n=strlen(s+1),m=strlen(t+1);
	for(int i=1;i<=n;++i)
	if(s[i]=='A') a[i]=1;
	else if(s[i]=='T') a[i]=2;
	else if(s[i]=='C') a[i]=3;
	else if(s[i]=='G') a[i]=4;
	for(int i=1;i<=m;++i)
	if(t[i]=='A') b[i]=1;
	else if(t[i]=='T') b[i]=2;
	else if(t[i]=='C') b[i]=3;
	else if(t[i]=='G') b[i]=4;
	dfs(0,0,0,0);
	printf("%d",ans);
    return 0;
}
    
* dalao的一个小技巧? 再往下不可能的话就退出 (有点像迭代加深搜索的乐观估计剪枝?

D[i,j]表示原材料已经去掉了前i个,目标链已经生成了前j个所需的最小花费。

​ 定义:d[i,j,0]表示使用任意方法达到状态D[i,j]的最少时间,d[i,j,1]与d[i,j,2]表示最后一次使用正向与反向切割拷贝的方法达到状态D[i,j]的最少时间,d[i,j,3]表示最后一次使用删除原串的方法达到状态D[i,j]的最少时间。

​ 递归方程式:

\(d[i,j,0]=\begin{cases}d[i,j,1/2/3]\\d[i,j-1,0]+c_3\end{cases}\)

\(if(s[i]==t[j])\) \(d[i,j,1]=min\begin{cases}d[i-1,j-1,1]\\d[i-1,j-1,0]+c_1\end{cases}\)

\(if(s[i]==match[t[j]])\) \(d[i,j,2]=min\begin{cases}d[i-1,j-1,2]\\d[i-1,j-1,0]+c_1\end{cases}\)

\(d[i,j,3]=min\begin{cases}d[i-1,j,0]+c_2\\d[i-1,j,3]\end{cases}\)

暂时真的不想去写滚动数组的版本辽...

80昏
#include
using namespace std;
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
const int N=3000+5,M=1e5+5,inf=0x3f3f3f3f,P=19650827;
int n,m,ans=inf,c1,c2,c3,f[N][N][4];
char s[N],t[N];
template void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}
char match(char x){
	if(x=='A') return 'T';
	if(x=='T') return 'A';
	if(x=='C') return 'G';
	if(x=='G') return 'C';
}
int main(){
	freopen("T2.txt","r",stdin);
//	freopen("DNA.out","w",stdout);
	rd(c1),rd(c2),rd(c3);
	scanf("%s",s+1);scanf("%s",t+1);
	n=strlen(s+1),m=strlen(t+1);
	memset(f,inf,sizeof(f));
	f[0][0][0]=0;
	for(int i=1;i< = m;++i) f[0][i][0]=i*c3;
	for(int i=1;i< = n;++i) f[i][0][0]=c2;
	for(int i=1;i< = n;++i){
		for(int j=1;j< = m;++j){
			if(s[i]==t[j]) f[i][j][1]=Min(f[i-1][j-1][1],f[i-1][j-1][0]+c1);
			if(s[i]==match(t[j])) f[i][j][2]=Min(f[i-1][j-1][2],f[i-1][j-1][0]+c1);
			f[i][j][3]=Min(f[i-1][j][3],f[i-1][j][0]+c2);
			f[i][j][0]=Min(f[i][j][1],Min(f[i][j][2],f[i][j][3]));
			f[i][j][0]=Min(f[i][j][0],f[i][j-1][0]+c3);
		}
	}
	for(int i=0;i< = n;++i) ans=Min(ans,f[i][m][0]);
	printf("%d",ans);
    return 0;
}

其实有做过一道类似的题 也是两个串 那个是直接的数字 操作也差不多 只是我忘了...

好叭...是我记错了luogu2758是这个的超级弱化版?QAQ

考试的时候想出来了状态的那个数组就是\(f[i][j][0/1/2]\)材料的前i个来拼目标的前j个操作是第1/2/3个

只是懒得想了...

危险的迷宫

我没有去复习网络流...前几天做匈牙利算法的时候我就该想到...可是我就是不想看

这个应该是边的数量达150以上就T了 \(10\times10\)最多就\(180\)条通路 所以暴搜选手必须要拥有姓名

只是我没有看到无解的情况下输出-1...(我还想到无解咋整啊 既然他没说那就铁定是保证有解 结果他说了我没看到)

80昏
#include
using namespace std;
#define ll long long
#define rg register
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
const int N=10+5,M=150000+5,inf=0x3f3f3f3f,P=19650827;
int A,B,n,k,ans=0,mp[N][N],st[1000],ed[1000],ided[N][N];
bool vis[150],ton[105][105];
template void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}
int adr(int x,int y){return (x-1)*B+y;}
void dfs(int u,int sum,int cnt){
	if(sum>=ans) return;
	int xu=u/B+1,yu=u%B;
	if(!yu) yu=B,--xu;
	sum+=mp[xu][yu],vis[u]=1;
	if(ided[xu][yu]){
		++cnt;
		if(cnt==n){ans=Min(ans,sum);return;}
		dfs(st[cnt+1],sum,cnt);
	}
	else {
			int v;
			if(ton[u][v=u+B]&&!vis[v]) vis[v]=1,dfs(v,sum,cnt),vis[v]=0;
			if(ton[u][v=u-1]&&!vis[v]) vis[v]=1,dfs(v,sum,cnt),vis[v]=0;
			if(ton[u][v=u+1]&&!vis[v]) vis[v]=1,dfs(v,sum,cnt),vis[v]=0;
			if(ton[u][v=u-B]&&!vis[v]) vis[v]=1,dfs(v,sum,cnt),vis[v]=0;
	}
}
int main(){
	freopen("maze.in","r",stdin);
	freopen("maze.out","w",stdout);
	rd(A),rd(B);ans=inf;
	for(int i=1;i<=A;++i)
	for(int j=1;j<=B;++j) rd(mp[i][j]);
	rd(k);
	for(int i=1,x,y,x1,y1,X,Y;i<=k;++i)
	rd(x),rd(y),rd(x1),rd(y1),X=adr(x,y),Y=adr(x1,y1),ton[X][Y]=ton[Y][X]=1;
	rd(n);
	for(int i=1,x,y;i<=n;++i) rd(x),rd(y),st[i]=adr(x,y);
	for(int i=1,x,y;i<=n;++i) rd(x),rd(y),ed[i]=adr(x,y),ided[x][y]=1;
	dfs(st[1],0,0);
	if(ans!=inf) printf("%d",ans);
	else puts("-1");
    return 0;
} 

正解:网络流

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)>(y)?(y):(x))
const int N=1000+5,M=100000+5,inf=0x3f3f3f3f,P=19650827;
int A,B,n,tt,s,t,cnt=0,ans=0,pre[N];
template <class t>void rd(t &x){
    x=0;int w=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=w?-x:x;
}

int head[N],tot=1;
struct edge{int v,flo,cos,nxt;}e[N];
void add(int u,int v,int flo,int cos){
	e[++tot]=(edge){v,flo,cos,head[u]},head[u]=tot;
	e[++tot]=(edge){u,0,-cos,head[v]},head[v]=tot;
}
int adr(int i,int j){return (i-1)*B+j;}

int dis[N];
queue<int> q;bool vis[N];
bool spfa(){
	memset(vis,0,sizeof(vis));
	memset(dis,inf,sizeof(dis));
	q.push(s),vis[s]=1,dis[s]=0;
	while(!q.empty()){
		int u=q.front();q.pop(),vis[u]=0;
		for(int i=head[u],v,flo,cos;i;i=e[i].nxt){
			if(!(flo=e[i].flo)) continue;
			if(dis[(v=e[i].v)]>dis[u]+(cos=e[i].cos)){
				dis[v]=dis[u]+cos,pre[v]=i;
				if(!vis[v]) q.push(v),vis[v]=1;
			}
		}
	}
	return dis[t]!=inf;
}

void upd(){
	int x=t;
	while(x!=s){
		int i=pre[x];
		e[i].flo-=1,e[i^1].flo+=1;
		x=e[i^1].v;
	}
	ans+=dis[t];
}

int main(){
	freopen("in2.txt","r",stdin);
//	freopen("DNA.out","w",stdout);
	rd(A),rd(B);tt=A*B;
	s=(tt<<1)+1,t=s+1;
	for(int i=1;i<=A;++i)
	for(int j=1,val,x,y;j<=B;++j){
		rd(val);x=adr(i,j),y=x+tt;
		add(x,y,1,val);
	}
	rd(n);
	for(int i=1,x,y,x2,y2,X,Y;i<=n;++i){
		rd(x),rd(y),rd(x2),rd(y2);
		X=adr(x,y),Y=adr(x2,y2);
		add(X+tt,Y,1,0),add(Y+tt,X,1,0);
	}
	rd(n);
	for(int i=1,x,y;i<=n;++i) rd(x),rd(y),add(s,adr(x,y),1,0);
	for(int i=1,x,y;i<=n;++i) rd(x),rd(y),add(adr(x,y)+tt,t,1,0);
	while(spfa()) ++cnt,upd();
	if(cnt==n) printf("%d",ans);
	else puts("-1");
    return 0;
}

summary

  • 不要瓜想!不要瓜想!
  • 如果真的没有好的想法之后就先把暴力程序打好
  • 正确 冷静分析
posted @ 2019-08-24 15:25  委屈的咸鱼鱼鱼鱼  阅读(151)  评论(0编辑  收藏  举报