从零单排14

学习遇到瓶颈了。。

o(︶︿︶)o 唉。。

先贴提纲应该进行到的地方

大一假期(如果留校集训)
1. 掌握C++语法,并熟练使用STL  //正在学习。。还好
2. 试着实现STL的一些基本容器和函数,使自己基本能看懂STL源码  //还好
3. 图论
a) 使用优先队列优化Dijkstra和Prim   //有一点懂
b) 单源最短路径之SPFA  //之前实现过
c) 差分约束系统 //完全不懂
d) 多源多点最短路径之FloydWarshall算法  //之前实现过
e) 求欧拉路(圈套圈算法) //完全不懂+1
4. 进行复杂模拟题训练 //额。。还未练习
5. 拓扑排序 //至少未涉及并查集的部分感觉还是比较简单的
6. 动态规划进阶 
a) 完全背包、多重背包等各种背包问题(参见背包九讲)//目前只掌握了01,完全和多重。。
b) POJ上完成一定数目的动态规划题目 //以下未进行
c) 状态压缩动态规划
d) 树形动态规划
7. 搜索
a) 回溯法熟练应用
b) 复杂的搜索题目练习
c) 双向广度优先搜索
d) 启发式搜索(包括A*算法,如八数码问题)
8. 计算几何
a) 判断点是否在线段上
b) 判断线段相交
c) 判断矩形是否包含点
d) 判断圆与矩形关系
e) 判断点是否在多边形内
f) 判断点到线段的最近点
g) 计算两个圆的公切线
h) 求矩形的并的面积
i) 求多边形面积
j) 求多边形重心
k) 求凸包
选修
9. 可以学习一种C++的开发框架来编写一些窗体程序玩玩(如MFC,Qt等)。
10. 学习使用C或C++连接数据库。


背包这一块好难啊。。。

自己还没有充分理解背包九讲的内容。。

囧。。

今天上午看了优先队列优化的prim和dijkstra,感觉马马虎虎。。

下午开始的时候看了拓扑排序也还挺简单。。。

找了背包题目的集合来做。。。

01完全和多重完全就是处理一下输入输出,然后套模版。。。

一到其他各种背包就手足无措了。。

关键是没有理解它的含义。。

不能再这样继续盲目做下去。。。

总结反思。。


贴几道今天的成果。。

hdu 1285:http://acm.hdu.edu.cn/showproblem.php?pid=1285

/*
基本的拓扑排序
懂了思想编码就很快了
寻找入度为0的点->该点指向的所有点入度-1
*/
#include<iostream>
using namespace std;
int map[505][505];
int indegree[505];
int ans[505];
int n,m;
void toposort()
{
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			if(map[i][j])
			{
				indegree[j]++;
			}
		}
	}
	for(int i=1;i<=n;i++)
	{
		int j=1;
		while(indegree[j]!=0)
		{
			j++;
		}
		ans[i]=j;
		indegree[j]--;
		for(int k=1;k<=n;k++)
		{
			if(map[j][k])
			{
				indegree[k]--;
			}
		}
	}
}
int main()
{
	while(cin>>n>>m)
	{
		memset(indegree,0,sizeof(indegree));
		memset(map,0,sizeof(map));
		while(m--)
		{
			int x,y;
			cin>>x>>y;
			map[x][y]=1;
		}
		toposort();
		for(int i=1;i<n;i++)
		{
			cout<<ans[i]<<" ";
		}
		cout<<ans[n]<<endl;
	}
	system("pause");

	return 0;
}

hdu 3342: http://acm.hdu.edu.cn/showproblem.php?pid=3342

/*
拓扑排序应用,若一次遍历无indegree=0的点则说明存在环
*/
#include <iostream>
using namespace std;
int map[105][105];
int indegree[105];
int n,m;
void toposort()
{
	for(int i=0;i<n;++i)
    {
    	bool flag = false;      //用于标识在一次排序中是否有环 
        for(int j=0;j<n;++j)
        {
            if(indegree[j]==0)
            {
                flag=true;
                indegree[j]--;
                for(int k=0;k<n;++k)
                {
                    if(map[j][k])
                        indegree[k]--;
                }
                break;
            }
        }
        if(!flag)
        {
            cout<<"NO"<<endl;
        	return ;
        }
    }
	cout<<"YES"<<endl;
}
int main()
{
    while(cin>>n>>m&&n!=0)
    {
        memset(indegree,0,sizeof(indegree));
        memset(map,0,sizeof(map));
        while(m--)
        {
			int x,y;
            cin>>x>>y;
            if(map[x][y]==0)
            {
                map[x][y]=1;
                indegree[y]++;
            }
        }
        toposort();
    }
    system("pause");
    return 0;
}

/*
poj 3624
这题不是hdu上的啊。。
不过一样是模版01背包。。
*/
#include<iostream>
using namespace std;
int f[13000];
int n,m;
void ZeroOnePack(int cost,int weight)//cost 为费用, weight 为价值 
{
    for(int i=m;i>=cost;i--)
       if(f[i-cost]+weight>f[i]) 
	   		f[i]=f[i-cost]+weight;
}    
void CompletePack(int cost,int weight)
{
    for(int i=cost;i<=m;i++)
        if(f[i-cost]+weight>f[i]) 
			f[i]=f[i-cost]+weight;
}         
void MultiplePack(int cost ,int weight,int amount)
{
    if(cost*amount>=m) 
		CompletePack(cost,weight);
    else
    {
        for(int k=1;k<amount;)
        {
            ZeroOnePack(k*cost,k*weight);
            amount-=k;
            k<<=1;
        }    
        ZeroOnePack(amount*cost,amount*weight);
    }    
}    
int main()
{
	while(cin>>n>>m)
	{
		for(int i=0;i<n;i++)
		{
			int cost,weight;
			cin>>cost>>weight;
			ZeroOnePack(cost,weight);
		}
		cout<<f[m]<<endl;
	}
	system("pause");
	return 0;
}

/*
poj 3628
理解背包模版中各个量的含义
*/
#include<iostream>
using namespace std;
int f[1000005];
int c[1000005];
int n,m,sum;
void ZeroOnePack(int cost,int weight)//cost 为费用, weight 为价值 
{
    for(int i=sum;i>=cost;i--)
       if(f[i-cost]+weight>f[i]) 
	   		f[i]=f[i-cost]+weight;
} 
int main()
{
	while(cin>>n>>m)
	{
		memset(f,0,sizeof(f));
		sum=0;
		for(int i=1;i<=n;i++)
		{
			cin>>c[i];
			sum+=c[i];
			ZeroOnePack(c[i],c[i]);
		}
		for(int i=1;i<=sum;i++)
		{
//			cout<<f[i]<<endl;
			if(f[i]>=m)
			{
				cout<<f[i]-m<<endl;
				break;
			}
		}
	}
	system("pause");
	return 0;
}

/*
想不出。。。
题解见:http://blog.youkuaiyun.com/lyy289065406/article/details/6648094
写的真好。。。
*/
//Memory Time 
//1496K  0MS 

//我所使用的解题方法,由于dp状态方程组申请空间比较大大
//若dp为局部数组,则会部分机器执行程序时可能由于内存不足会无法响应
//所以推荐定义dp为全局数组,优先分配内存

#include<iostream>
using namespace std;

int dp[21][15001]; //状态数组dp[i][j]
	                   //放入(挂上)前i个物品(钩码)后,达到j状态的方法数
int main(int i,int j,int k)
{
	int n;  //挂钩数
	int g;  //钩码数
	int c[21];  //挂钩位置
	int w[21];  //钩码重量

	
	/*Input*/

	cin>>n>>g;

	for(i=1;i<=n;i++)
		cin>>c[i];
	for(i=1;i<=g;i++)
		cin>>w[i];

	/*Initial*/

	memset(dp,0,sizeof(dp));  //达到每个状态的方法数初始化为0
	dp[0][7500]=1;     //7500为天枰达到平衡状态时的平衡度
	                   //放入前0个物品后,天枰达到平衡状态7500的方法有1个,就是不挂钩码

	/*DP*/

	for(i=1;i<=g;i++)
		for(j=0;j<=15000;j++)
			if(dp[i-1][j])  //优化,当放入i-1个物品时状态j已经出现且被统计过方法数,则直接使用统计结果
				            //否则忽略当前状态j
				for(k=1;k<=n;k++)
					dp[i][ j+w[i]*c[k] ] += dp[i-1][j]; //状态方程
	
	/*Output*/

	cout<<dp[g][7500]<<endl;
	return 0;
}

/*
注意递推公式
减法原理应用
其他没什么了 
*/
#include<iostream>
#include<cstdio>
using namespace std;
double f[10005];
int n;
int m;
void ZeroOnePack(int cost,double weight)//cost 为费用, weight 为价值 
{
    for(int i=n;i>=cost;i--)
       if(1-(1-f[i-cost])*(1-weight)>f[i]) 
	   		f[i]=1-(1-f[i-cost])*(1-weight);
}    
int main()
{
	while(cin>>n>>m,n!=0||m!=0)
	{
		memset(f,0,sizeof(f));
		for(int i=0;i<m;i++)
		{
			int cost;
			double p;
			cin>>cost>>p;
			ZeroOnePack(cost,p);
		}
		printf("%.1lf%%\n",f[n]*100);
	}
	system("pause");
	return 0;
}

 /*
注意初始化f[0]=1,表示未偷时是安全的,其它初始化为0,表示不安全 
 */
 #include<iostream>
 #include<cstdio>
 #include<cmath>
 #define MAXN 101
 #define MAXV 10001
 using namespace std;
 int cost[MAXN];
int v,k;
 double weight[MAXV],f[MAXV];
  void ZeroOnePack(int cost,double weight)//cost 为费用, weight 为价值 
{
    for(int i=v;i>=cost;i--)
       if(f[i-cost]*weight>f[i]) 
	   		f[i]=f[i-cost]*weight;
}    
 int main()
 {
     int T,n,i,j;
     double P;
     cin>>T;
     while(T--)
     {
         cin>>P>>n;
         P=1-P;
         v=0;
         for(i=0;i<n;i++)
         {
             cin>>cost[i]>>weight[i];
             weight[i]=1-weight[i];
             v+=cost[i];
         }
         memset(f,0,sizeof(f));;
         f[0]=1;
         for(i=0;i<n;i++)
         {
			ZeroOnePack(cost[i],weight[i]);
		}
         bool flag=false;
         for(i=v;i>=0;i--)
         {
             if(f[i]-P>0.000000001)
             {
                 printf("%d\n",i);
                 break;
             }
         }
     }
     return 0;
 }

/*
二维01背包
不会
学习
题目描述:给最多40根木棍,每根长度不超过40,
要用完所有的木棍构成面积最大的三角形,
求出最大的面积。

算法核心:二维01背包
  使用到海伦公式:
  已知三角形的三边长度a,b,c,求面积
   S=√[p(p-a)(p-b)(p-c)]
  而公式里的p为半周长: 
  p=(a+b+c)/2

分析:用dp[i][j][k]表示到第i根木棒能否摆出边长分别为j,k的三角形
     易得 dp[i][j][k] = dp[i-1][j-x[i]][k]|dp[i-1][j][k-x[i]]|dp[i-1][j][k];
  简单的空间压缩,化为二维dp,注意:这里每根木棒只能使用一次,
  是01背包,要倒着扫
*/
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
using namespace std;
int x[41],n,tot=0,ans=-1,half;
bool dp[801][801];
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>x[i];
        tot+=x[i];
    }
    memset(dp,0,sizeof(dp));
    dp[0][0]=1;
	half=tot/2;
    for(int i=1;i<=n;i++)
        for(int j=half;j>=0;j--)
            for(int k=j;k>=0;k--)
                if(j>=x[i]&&dp[j-x[i]][k] || k>=x[i]&&dp[j][k-x[i]])
                    dp[j][k]=1;
    for(int i=half;i>=1;i--)
        for(int j=i;j>=1;j--)
            if(dp[i][j])
            {
                int k=tot-i-j;
                if(i+j>k && i+k>j && j+k>i)
                {
                    double p=(i+j+k)*1.0/2;
                    int temp=(int)(sqrt(p*(p-i)*(p-j)*(p-k))*100);
                    if(temp>ans)
                        ans=temp;
                }
            }
    cout<<ans<<endl;
    return 0;
}

/*
分组背包
不会
学习
http://blog.sina.com.cn/s/blog_6ec19c780100w1nn.html
http://blog.youkuaiyun.com/ice2013/article/details/7731539
分组背包问题,大意**要买鞋,有k种牌子,每种牌子至少买一双鞋子。每双鞋子有标价跟实际价值。求用m多的钱买最多价值的鞋。
 
其实我觉得这题的难点就在处理“至少”这点上面。
 
状态方程很多都能推出用 dp[k][m] 来表示 已经买了k种鞋 在有m钱状态下的 鞋的最大价值。
 
状态转移方程为
 
        for( k = 1 ; k <= K ; k++)
        {
            for( i = 0 ; i < num[k] ; i++)
            {
                for( j = mm ; j >= m[k][i].m ; j--)
                {
                    if(dp[k][j - m[k][i].m] != -1)
                        dp[k][j] = Max(dp[k][j] , dp[k][j - m[k][i].m] + m[k][i].v);
                    if(dp[k-1][j - m[k][i].m] != -1 )
                        dp[k][j] = Max(dp[k][j] , dp[k-1][j - m[k][i].m] + m[k][i].v);

                }
            }
        }
如果忽略了两个红色的判断句,大家都看得出这只是单纯的01背包且 没有条件限制,加了这两句就能实现至少了。理由如下
 
一开始我将dp[][]数组初始化为-1表示所有的数都不合法。大于0表示合法
然后将所有的 k = 0 dp[0][]置为0,这是为了 k = 1时能合法计算。
 
从状态方程中看出,当上一个状态值为-1时表示他不合法。所以当前状态没有计算的必要也不合法答案。
 
如果计算完第k类商品的取值后,所有的dp[k][]均为-1的时候,第k类表明没有一鞋被买。故所有状态都不合法,接下来的所有值也都将不合法。
 
在计算第k组商品的过程中,当某个-1变成一个非负数的时候,也就表明当前的第k种已经拿了第i件物品,所以变成合法答案了。
 
如此推下去,最后一个值dp[k][m],就是答案了。如果依然是-1,就输出impossible把。
*/
#include <math.h>
#include <stdio.h>
#include <string.h>
#include<iostream>
#include <algorithm>
using namespace std;
#define maxn 10005
//#define LOCAL
#define CLR( a , b )  memset( a , b ,sizeof(a) )
int dp[11][maxn] , c[100] , v[100] , N , M , K , Bag[11][101] , Sum[11] ;
int main() {
   #ifdef LOCAL
      freopen("Input.txt","r",stdin);
      freopen("Output.txt","w",stdout);
   #endif
      int i , j , k , x ;
      while( ~scanf( "%d%d%d" , &N , &M , &K) ){
            CLR( Sum , 0 ) ;
            for( i = 0 ; i < N ; i++ ){
                  scanf( "%d%d%d" , &x , &c[i] , &v[i] ) ;
                  Bag[x][ Sum[x] ] = i ;     //记录到该品牌
                  Sum[x] ++ ;                    //控制个数
            }
            memset( dp , -1 , sizeof(dp) ) ;
            for( i = 0 ; i <= M ; i++ ){   //初始化
                  dp[0][i] = 0 ;
            }
            for( i = 1 ; i <= K ; i++ )          //品牌编号
                  for( j = 0 ; j < Sum[i] ; j++ )      //该编号个数
                        for( k = M ; k >= c[Bag[i][j]] ; k-- ){
                              if( dp[i][ k-c[ Bag[i][j] ] ] != -1 )
                                    dp[i][k] = max( dp[i][k] , dp[i][ k-c[Bag[i][j]] ] + v[Bag[i][j] ] ) ;
                              if( dp[i-1][ k-c[ Bag[i][j]] ] != -1 )
                                    dp[i][k] = max( dp[i][k] , dp[ i-1 ][ k-c[Bag[i][j]] ] + v[Bag[i][j] ] ) ;
                        }
            if( dp[K][M] < 0 )
                  printf( "Impossible\n" ) ;
            else
                  printf( "%d\n" , dp[K][M] ) ;
      }
      return 0;
}

/*
分组背包模版
*/
#include<iostream>
#include <algorithm>
using namespace std;
#define MAXN 105

int dp[MAXN];
int map[MAXN][MAXN];

void Group_OneZeroPack(int n,int m)
{
	for(int i=1;i<=n;i++ )
    	for(int j=m;j>=0;j--)
            for(int k=1;k<=j;k++ )
                dp[j]=max(dp[j],dp[j-k]+map[i][k]);
}

int main()
{
	int M , N , i , j , temp ;
    while(cin>>n>>m,n!=0&&m!=0)
	{
    	memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
        	for(j=1;j<=m;j++ )
            	cin>>map[i][j];
        Group_OneZeroPack(n,m);
        cout<<dp[m]<<endl;
    }
    return 0;
}

/*
混合背包
像我这种连分组背包都没有掌握的人果然不适合做这题。。
网上搜的题解
http://www.cnblogs.com/ACMan/archive/2012/08/13/2637022.html
*/
 
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 1<<29
int n, m, sum, g;
int w[101],p[101];
int dp[101][101];
int main()
{
    int i, j, x;
    while(~scanf("%d%d",&n,&sum))
    {
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&m,&g);
            for(x=1;x<=m;x++)
                scanf("%d%d",&w[x],&p[x]);
            if(g==0)
            {
                for(j=0;j<=sum;j++)//当前组初始化
                    dp[i][j]=-INF;
                for(x=1;x<=m;x++)
                    for(j=sum;j>=w[x];j--)
                        dp[i][j]=max(dp[i][j],max(dp[i][j-w[x]]+p[x],dp[i-1][j-w[x]]+p[x]));
            }
            else if(g==1)
            {
                for(j=0;j<=sum;j++) //当前组初始化
                    dp[i][j]=dp[i-1][j];
                for(x=1;x<=m;x++)
                    for(j=sum;j>=w[x];j--)
                            dp[i][j]=max(dp[i][j],dp[i-1][j-w[x]]+p[x]);
            }
            else if(g==2)
            {
                for(j=0;j<=sum;j++) //当前组初始化
                    dp[i][j]=dp[i-1][j];
                for(x=1;x<=m;x++)
                    for(j=sum;j>=w[x];j--)
                        dp[i][j]=max(dp[i][j],dp[i][j-w[x]]+p[x]);
            }

        }
        dp[n][sum]=max(dp[n][sum],-1); //没有完成任务的值都为负的,做输出调整,输出-1
        printf("%d\n",dp[n][sum]);
    }
    return 0;
}

加油。

### C语言学习路径 为了成为百强级别的C语言程序员,需遵循一条系统的成长路线。这条路线不仅涵盖了基础知识的学习,还包括实践项目的积累和技术深度的理解。 #### 基础阶段:掌握核心概念 在这个阶段,重点应放在理解C语言的基础语法和特性上。这包括变量声明、数据类型、运算符、控制流语句(if/else, switch)、循环结构(for, while),以及函数定义与调用[^1]。 ```c #include <stdio.h> int main() { int a = 5; printf("Value of a is %d\n", a); return 0; } ``` #### 进阶阶段:深入探索高级主题 随着对基本概念的熟悉度增加,可以转向更复杂的话题,比如指针操作、内存管理、文件I/O处理、动态分配数组等。这些知识点对于编写高效可靠的程序至关重要[^2]。 ```c // 动态分配内存的例子 #include <stdlib.h> void* safe_malloc(size_t size){ void *ptr = malloc(size); if(ptr == NULL){ fprintf(stderr,"Out of memory"); exit(1); } return ptr; } ``` #### 实践应用:构建实际项目经验 理论知识固然重要,但真正的提升来自于动手做项目。可以选择参与开源项目贡献代码,或是自己发起一些小型的应用开发工作来锻炼解决问题的能力。通过不断尝试新的挑战,逐步建立起解决各种问题所需的技能集[^3]。 #### 技术深化:关注性能优化与安全编码 当具备了一定的经验之后,应该更加注重于如何写出高性能且安全性高的代码。了解编译器的工作原理可以帮助更好地利用底层资源;而学习常见的漏洞防范措施则能有效减少潜在风险[^4]。 ### 编程技巧 - **阅读优秀源码**:经常浏览高质量的开源库或工具包中的实现细节,从中汲取灵感。 - **练习算法题目**:定期参加在线竞赛平台上的刷题活动,强化逻辑思维能力。 - **保持好奇心**:积极跟踪行业最新趋势和发展方向,持续更新自己的知识体系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值