Pornire rapidă „Numere în C#”

Introducere

Această pornire rapidă vă învață despre tipurile de numere în C# în mod interactiv, folosind browser-ul pentru a scrie C# și a vedea rezultatele compilării și rulării codului dvs. Ea conține o serie de lecții care explorează numere și operații matematice în C#. Aceste lecții vă învață elementele fundamentale ale limbajului C#.

Explorați matematica numerelor întregi

Rulați codul următor în fereastra interactivă. Pentru a face aceasta, tastați următorul bloc de cod în fereastra interactivă și faceți clic pe butonul Run:

int a = 18;
int b = 6;
int c = a + b;
Console.WriteLine(c);

Tocmai ați văzut una dintre operațiile matematice fundamentale cu întregi. Tipul int reprezintă un întreg, un pozitiv sau negativ număr întreg. Folosiți simbolul + pentru adunare. Alte operații matematice pentru întregi includ:
  • - pentru scădere
  • * pentru înmulțire
  • / pentru împărțire
Sfat. De-a lungul acestei porniri rapide, puteți explora dvs. înșivă modificând codul pe care l-ați scris în fereastra interactivă. Această pornire rapidă oferă exemple pe care le puteți încerca la fiecare pas.

Începeți prin a explora toate aceste operații diverse. Modificați a treia linie pentru a încerca fiecare din aceste operații. După fiecare editare, faceți clic pe butonul Run.

Scădere:

int c = a - b;

Înmulțire:

int c = a * b;

Împărțire:

int c = a / b;

Puteți de asemenea experimenta făcând mai multe operații matematice în același rând, dacă doriți.

Sfat. În timp ce explorați C# (sau oricare limbaj de programare), veți face greșeli când scrieți cod. Compilatorul va găsi aceste erori și vi le va raporta. Când ieșirea conține mesaje de eroare, priviți atent la codul exemplu și la codul din fereastra interactivă pentru a vedea ce să reparați. Acest exercițiu vă va ajuta să învățați structura codului C#.

Explorați ordinea operațiilor

Limbajul C# definește precedența a diferiți operatori matematici cu reguli consistente cu regulile pe care le-ați învățat în matematică. Înmulțirea și împărțirea au precedență mai mare decât adunarea și împărțirea. Explorați aceasta rulând următorul cod în fereastra interactivă:

int a = 5;
int b = 4;
int c = 2;
int d = a + b * c;
Console.WriteLine(d);

Ieșirea demonstrează că înmulțirea este efectuată înaintea adunării.

Puteți forța o ordine diferită de operare adăugând paranteze în jurul operației sau operațiilor pe care le doriți efectuate mai întâi:

int a = 5;
int b = 4;
int c = 2;
int d = (a  + b) * c;
Console.WriteLine(d);

Explorați mai departe combinând mulți diferiți operatori. Înlocuiți linia a patra de deasupra cu ceva asemănător cu asta:

int d = (a + b) - 6 * c + (12 * 4) / 3 + 12;

Poate ați observat un comportament interesant pentru numerele întregi. Împărțirea întregilor întotdeauna produce un rezultat întreg, chiar și atunci când v-ați aștepta ca rezultatul să includă o parte zecimală sau fracțională.

Dacă nu ați văzut acest comportament, încercați următorul:

int a = 7;
int b = 4;
int c = 3;
int d = (a  + b) / c;
Console.WriteLine(d);

Faceți clic pe Run din nou pentru a vedea rezultatele.

Explorați precizia și limitele numerelor întregi

Ultimul exemplu v-a arătat că împărțirea întreagă trunchiază rezultatul. Puteți obține restul folosind operatorul modulo, caracterul %.

int a = 7;
int b = 4;
int c = 3;
int d = (a  + b) / c;
int e = (a + b) % c;
Console.WriteLine($"cat: {d}");
Console.WriteLine($"rest: {e}");

Tipul întreg din C# diferă de tipul matematic număr întreg în încă un mod: tipul int are limite minimă și maximă. Rulați acest cod în fereastra interactivă pentru a vedea aceste limite.

int max = int.MaxValue;
int min = int.MinValue;
Console.WriteLine($"Intervalul de intregi este de la {min} la {max}");

Dacă un calcul produce o valoare care trece de aceste limite, aveți o condiție de underflow sau overflow (condiție de depășire). Răspunsul pare să înfășoare de la o limită la alta. Adăugați aceste două linii la fereastra interactivă pentru a vedea un exemplu:

int what = max + 3;
Console.WriteLine($"Un exemplu de depasire pozitiva (overflow): {what}");

Observați că răspunsul este foarte aproape de cel mai mic întreg (negativ). Este la fel ca min + 2. Operația de adunare a depășit pozitiv valorile permise pentru întregi. Răspunsul este un foarte mare număr negativ deoarece o depășire pozitivă "se întoarce" de la cea mai mare valoare posibilă întreagă la cea mai mică.

Există alte tipuri numerice cu diferite limite și precizie pe care le-ați folosi când tipul int nu vă împacă nevoile. Haideți să le explorăm pe acestea în continuare.

Lucrați cu tipul double

Tipul numeric double reprezintă un număr în virgulă mobilă de precizie dublă. Acești termeni ar putea fi noi pentru dvs. Un număr în virgulă mobilă este folositor pentru a reprezenta numere ne-întregi care ar putea fi foarte mari sau mici în dimensiune. Precizie dublă înseamnă că aceste numere sunt stocate folosind precizie mai mare decât precizie simplă. Pe calculatoarele moderne, este mai comun să se folosească precizie dublă decât numere de precizie simplă. Haideți să explorăm. Încercați următorul cod în fereastra interactivă și vedeți rezultatul:

double a = 5;
double b = 4;
double c = 2;
double d = (a  + b) / c;
Console.WriteLine(d);

Observați că răspunsul include partea zecimală a câtului. Încercați o expresie puțin mai complicată cu double-uri:

double a = 19;
double b = 23;
double c = 8;
double d = (a  + b) / c;
Console.WriteLine(d);

Intervalul unei valori double este mult mai mare decât valorile întregi. Încercați următorul cod în fereastra interactivă:

double max = double.MaxValue;
double min = double.MinValue;
Console.WriteLine($"Intervalul lui double este de la {min} la {max}");

Valorile acestea sunt tipărite în notație științifică. Numărul din stânga lui E este significandul. Numărul din dreapta este exponentul, ca o putere a lui 10.

La fel ca numerele zecimale în matematică, numerele double în C# pot avea erori de rotunjire. Încercați acest cod:

double third = 1.0. / 3.0;
Console.WriteLine(third);

Știți că 0.3 cu 3 repetându-se nu este exact același cu 1/3.

Provocare

Încercați alte calcule cu numere mari, numere mici, înmulțire și împărțire folosind tipul double. Încercați calcule mai complicate.

Lucrați cu tipuri în virgulă fixă

Ați văzut tipurile numerice de bază în C#: întregi și double-uri. Există un alt tip de învățat: tipul decimal. Tipul decimal are un interval mai mic dar precizie mai mare decât double. Termenul virgulă fixă înseamnă că punctul zecimal (sau punct binar) nu se mișcă. Haideți să aruncăm o privire:

decimal min = decimal.MinValue;
decimal max = decimal.MaxValue;
Console.WriteLine($"Intervalul tipului decimal este între {min} și {max}");

Observați că intervalul este mai mic decât tipul double. Puteți vedea mai marea precizie cu tipul decimal încercând următorul cod:

double a = 1.0;
double b = 3.0;
Console.WriteLine(a / b);

decimal c = 1.0M;
decimal d = 3.0M;
Console.WriteLine(c / d);

Sufixul M pe numere este cum indicați că o constantă trebuie să folosească tipul decimal.

Observați că matematica folosind tipul decimal are mai multe cifre în dreapta punctului decimal.

Provocare

Acum că ați văzut diferite tipuri numerice, scrieți cod care calculează aria unui cerc a cărui rază este 2.50 centimetri. Țineți minte că aria unui cerc este raza ridicată la pătrat înmulțit cu PI. Un indiciu: .NET conține o constantă pentru PI, Math.PI pe care o puteți folosi pentru această valoare.

Ar trebui să obțineți un răspuns între 19 și 20.

Provocare finalizată

Ați venit cu ceva asemănător cu aceasta?

double raza = 2.50;
double aria = Math.PI * raza * raza;
Console.WriteLine(aria);


Încercați câteva alte formule dacă doriți.

Felicitări!

Ați încheiat pornirea rapidă „Numere în C#”.

Puteți învăța mai multe despre numere în C# în următoarele subiecte:
Tradus din această pagină oficială de documentație Microsoft.

Problemă de grafuri clasa a XI-a, matematică-informatică, informatică ne-intensiv

Enunț

Se consideră un graf neorientat cu n vârfuri și m muchii, al cărei matrice de adiacență este citită de la tastatură. Fișierul "graf.txt" conține mai multe secvențe de vârfuri, aflate una sub alta, vârfurile fiecărei secvențe fiind scrise pe câte un rând și separate prin spații (nu se cunoaște câte astfel de secvențe există în fișier). Scrieți un program care afișează pe ecran acele secvențe de vârfuri din fișierul de intrare ce constituie lanțuri în graful dat, precizând pentru fiecare lanț dacă este elementar sau ne-elementar, apoi determină lanțul (lanțurile) de lungime maximă (reamintim că lungimea unui lanț este dată de numărul vârfurilor componente.

Exemplu

graf.txt:
1 2 6
8 7 6 1
3 4 5 3 2 8
5 3 2 7
1 2 8

fisier.in (în enunț, citit de la tastatură):
8 9
1 1 0 0 0 1 0 1
1 1 1 0 0 0 0 1
0 1 1 1 1 0 0 0
0 0 1 1 1 0 0 0
0 0 1 1 1 0 0 0
1 0 0 0 0 1 1 0
0 0 0 0 0 1 1 1
1 1 0 0 0 0 1 1


Se afișează în consolă:
1.
NU ESTE LANT
2.
ESTE LANT
ESTE ELEMENTAR
3.
ESTE LANT
NU ESTE ELEMENTAR
4.
NU ESTE LANT
5.
ESTE LANT
ESTE ELEMENTAR
Lanturile de lungime maxima 5 sunt in lista de lanturi:
 - al 2-lea

Codul sursă

#include <fstream>
#include <vector>
#include <iostream>
#include <sstream>
using namespace std;

bool este_lant(int N, int M, vector<vector<int>> &A,
    char line[], int l)
{
    string str = line;
    istringstream s(str);

    vector<int> lant(0);
    int x;
    while (s >> x)
    {
        lant.push_back(x);
    }

    for (int i = 0; i < lant.size() - 1; ++i)
    {
        if (A[lant[i]][lant[i + 1]] == 0)
        {
            return false;
        }
    }
    return true;
}

bool este_elementar(int N, int M, vector<vector<int>> &A,
    char line[], int l)
{
    string str = line;
    istringstream s(str);

    vector<int> lant(0);
    int x;
    while (s >> x)
    {
        lant.push_back(x);
    }

    for (int i = 0; i < lant.size(); ++i)
    {
        for (int j = i + 1; j < lant.size(); ++j)
        {
            if (lant[i] == lant[j])
            {
                return false;
            }
        }
    }
    return true;
}

int main()
{
    int N, M;

    // primul fisier de intrare:
    ifstream in("fisier.in");
    in >> N >> M;
    vector<vector<int>> A(N + 1, vector<int>(N + 1));
    for (int i = 1; i <= N; ++i)
    {
        for (int j = 1; j <= N; ++j)
        {
            in >> A[i][j];
        }
    }
    in.close();


    // al doilea fisier de intrare:
    ifstream in2("graf.txt");

    // valorile de pe acelasi indice din vectorii
    // urmatori sunt asociate:
    vector<int> lungimi_lanturi(0);
    vector<int> id_lanturi(0);

    int id = 1;

    // va retine randul curent:
    char line[100];

    int l;
    do
    {
        // se citeste un rand intreg:
        in2.getline(line, 100);
        l = strlen(line);

        // randul este gol:
        if (l == 0) continue;

        // determina daca sirul de varfuri din randul curent
        // este un lant:
        bool e_lant = este_lant(N, M, A, line, l);

        // id este indicele (incepand de la 1) al randului curent:
        cout << (id++) << ". " << endl;

        // afiseaza daca este lant sau nu:
        cout << (e_lant ? "ESTE LANT" : "NU ESTE LANT") << endl;

        // daca e lant, se efectueaza verificari suplimentare:
        if (e_lant)
        {
            bool e_elementar = este_elementar(N, M, A, line, l);

            cout << (e_elementar ? "ESTE ELEMENTAR" : "NU ESTE ELEMENTAR") << endl;

            // se numara spatiile din rand pt. a afla lungimea
            // lantului:
            int spatii = 0;
            for (int i = 0; i < l; ++i)
            {
                if (line[i] == ' ')
                {
                    ++spatii;
                }
            }

            id_lanturi.push_back(id - 2);
            lungimi_lanturi.push_back(spatii);
        }
    } while (l > 0);
    
    in2.close();

    // se cauta lanturile de lungime maxima:
    int maxl = -1;
    for (int i = 0; i < id_lanturi.size(); ++i)
    {
        int lungime_lant = lungimi_lanturi[i];
        if (lungime_lant > maxl)
        {
            maxl = lungime_lant;
        }
    }

    cout << "Lanturile de lungime maxima " << maxl <<
        " sunt in lista de lanturi:" << endl;
    for (int i = 0; i < id_lanturi.size(); ++i)
    {
        int lungime_lant = lungimi_lanturi[i];
        if (lungime_lant == maxl)
        {
            cout << " - al " << (i + 1) <<
                "-lea" << endl;
        }
    }

    return 0;
}

Pornire rapidă „Hello World în C#”

Salut C#

Această pornire rapidă vă învață C# interactiv, folosind browser-ul pentru a scrie c# și a vedea rezultatele compilării și rulării codului dvs. Ea conține o serie de lecții care încep cu un program „Hello World”. Aceste lecții vă învață elementele fundamentale ale limbajului C#.

Rularea primului dvs. program C#

Rulați următorul cod în fereastra interactivă. Pentru a face asta, tastați următorul bloc de cod în fereastra interactivă și faceți clic pe butonul Run.

Console.WriteLine("Hello World!");

Felicitări! Ați rulat primul dvs. program C#. Este un simplu program care tipărește mesajul „Hello World!”. El a folosit metoda Console.WriteLine pentru a tipări acel mesaj. Console este tipul care reprezintă fereastra consolă. WriteLine este o metodă a tipului Console care tipărește o linie de text în acea consolă text.

Haideți să mergem înainte și să explorăm mai mult. Restul acestei lecții explorează lucrul cu tipul string, care reprezintă text în C#. Precum tipul Console, tipul string are metode. Metodele string lucrează cu text.

Declararea și folosirea variabilelor

Primul dvs. program a tipărit string-ul "Hello World!” pe ecran.

Sfat. Pe măsură ce explorați C# (sau oricare limbaj de programare), veți face greșeli când scrieți cod. Compilatorul va găsi acele erori și vi le va raporta. Când ieșirea conține mesaje de eroare, priviți de aproape la codul exemplu, și codul în fereastra interactivă pentru a vedea ce să reparați. Acel exercițiu vă va ajuta să învățați structura codului C#.

Primul dvs. program este limitat la tipărirea unui singur mesaj. Puteți scrie programe mai utile folosind variabile. O variabilă este un simbol pe care îl puteți folosi pentru a rula același cod cu valori diferite. Haideți să încercăm asta! Înlocuiți codul pe care l-ați scris în fereastra interactivă cu codul următor:

string aFriend = "Bill";
Console.WriteLine(aFriend);

Prima linie declară o variabilă, aFriend și îi atribuie o valoare, "Bill". A doua linie tipărește numele.

Puteți atribui valori diferite oricărei variabile pe care o declarați. Puteți schimba numele la unul dintre prietenii dvs. Adăugați aceste două linii în fereastra interactivă după codul pe care l-ați adăugat deja.

aFriend = "Maira";
Console.WriteLine(aFriend);

Observați că aceeași linie de cod tipărește 2 mesaje diferite, bazat pe valoarea stocată în variabila aFriend.

Probabil ați observat de asemenea că acest cuvânt, "Hello", lipsește în ultimele 2 mesaje. Haideți să rezolvăm asta acum. Modificați liniile care tipăresc mesajul în următorul:

Console.WriteLine("Hello " + aFriend);

Faceți clic pe Run din nou pentru a vedea rezultatele.

Ați folosit până acum + pentru a construi șiruri de caractere din variabile și șiruri constante. Există o cale mai bună. Puteți pune o variabilă între caracterele { și } pentru a-i spune lui C# să înlocuiasca acel text cu valoarea variabilei.

Aceasta se numește interpolarea șirurilor de caractere.

Dacă adăugați un $ înainte de ghilimelele de deschidere ale unui șir de caractere, puteți apoi include variabile, precum aFriend, înăuntrul șirurilor de caractere între acolade. Dați-i o încercare:

Console.WriteLine($"Hello {aFriend}");

Faceți clic pe Run din nou pentru a vedea rezultatele. În loc de "Hello {aFriend}", mesajul ar trebui să fie "Hello Maira".

Lucrul cu șirurile de caractere

Ultima dvs. editare a fost prima noatră privire la ce puteți face cu șirurile de caractere. Haideți să explorăm mai mult.

Nu sunteți limitați la o singură variabilă între acolade. Încercați aceasta:

string firstFriend = "Maria";
string secondFriend = "Sage";
Console.WriteLine($"My friends are {firstFriend} and {secondFriend}");

Pe măsură ce explorați mai mult cu șirurile de caractere, veți găsi că șirurile sunt mai mult decât o colecție de litere. Puteți afla lungimea unui șir folosind Length. Length este o proprietate a string și returnează numărul de caractere în acel șir de caractere. Adăugați următorul cod la sfârșitul ferestrei interactive:

Console.WriteLine($"The name {firstFriend} has {firstFriend.Length} letters.");
Console.WriteLine($"The name {secondFriend} has {secondFriend.Length} letters.");

Sfat. Acesta este un moment bun pentru a explora dvs. de unul singur. Ați învățat că Console.WriteLine() scrie text pe ecran. Ați învățat cum să declarați variabile și să concatenați șiruri împreună. Experimentați în fereastra interactivă. Fereastra are o funcție numită IntelliSense care face sugestii pentru ce puteți face. Tastați un . după d în firstFriend. Veți vedea o listă cu sugestii pentru proprietăți și metode pe care le puteți folosi.

Faceți mai multe cu șirurile de caractere

Ați folosit o metodă, Console.WriteLine, pentru a tipări mesaje. O metodă este un bloc de cod care implementează o acțiune. Ea are un nume, deci o puteți accesa.

Presupuneți că șirurile dvs. de caractere au spații la început sau la sfârșit pe care nu vreți să le afișați. Vreți să tundeți spațiile din șirurile de caractere. Metoda Trim și metodele conexe TrimStart și TrimEnd fac acea muncă. Dvs. puteți simplu să folosiți aceste metode pentru a elimina spațiile de la început și de la sfârșit. Încercați acest cod:

string greeting = "        Hello World!        ";
Console.WriteLine($"[{greeting}]");

string trimmedGreeting = greeting.TrimStart();
Console.WriteLine($"[{trimmedGreeting}]");

trimmedGreeting = greeting.TrimEnd();
Console.WriteLine($"[{trimmedGreeting}]");

trimmedGreeting = greeting.Trim();
Console.WriteLine($"[{trimmedGreeting}]");

Acest exemplu întărește două concepte importante pentru lucrul cu șiruri de caractere. Metodele care manipulează șiruri de caractere întorc noi obiecte string în loc să le modifice pe loc. Puteți vedea că fiecare apel la oricare din metodele Trim întoarce un nou string dar nu schimbă mesajul original.

Există alte metode disponibile pentru a lucra cu șiruri de caractere. De exemplu, probabil ați folosit o comandă caută și înlocuiește într-un editor sau procesor de texte înainte. Metoda Replace face ceva similar într-un șir de caractere. Ea caută pentru un subșir și il înlocuiește un un text diferit. Funcția Replace ia 2 parametri. Acestea sunt șirurile dintre paranteze. Primul șir este textul de căutat. Al doilea șir este textul cu care se înlocuiește. Încercați dvs. înșivă. Adăugați acest cod. Tastați-l înăuntru pentru a vedea indiciile cum începeți să tastați .Re după variabila sayHello.

string sayHello = "Hello World!";
Console.WriteLine(sayHello);
sayHello = sayHello.Replace("Hello", "Greetings");
Console.WriteLine(sayHello);

Alte două metode folositoare fac un șir ALL CAPS (toate literele mari de tipar) sau cu toate literele mici. Încercați codul următor. Tastați-l înăuntru pentru a vedea cum IntelliSense dă indicii cum începeți să tastați To:

Console.WriteLine(sayHello.ToUpper());
Console.WriteLine(sayHello.ToLower());

Căutați șiruri de caractere

Cealaltă parte a unei operații de caută și înlocuiește este să găsiți text într-un șir. Puteți folosi metoda Contains pentru căutare. Ea vă ajută dacă un șir conține un subșir înăuntrul lui. Încercați următorul cod pentru a explora Contains:

string songLyrics = "You say goodbye, and I say hello";
Console.WriteLine(songLyrics.Contains("goodbye"));
Console.WriteLine(songLyrics.Contains("greetingss"));

Metoda Contains returnează o valoare booleană care spune dacă șirul pe care l-ați căutt a fost găsit. O valoare booleană stochează o fie o valoare true (adevărat) sau false (fals). Veți învăța mai multe despre valorile booleane într-o lecție viitoare.

Provocare

Există două metode similare, StartsWith și EndsWith care de asemenea caută subșiruri într-un șir. Acestea găsesc un subșir la începutul sau la sfârșitul șirului. Încercați să modificați exemplele anterioare pentru a folosi StartsWith și EndsWith în loc de Contains. Căutați "You" sau "goodbye" la începutul unui șir. Căutați "hello" sau "goodbye" la sfârșitul unui șir.

Notă. Priviți punctuația dvs. când testați pentru text la sfârșitul șirului de caractere. Dacă șirul se sfârșește cu un punct, trebuie să verificați pentru un șir care se sfârșește cu un punct.

Ar trebui să obțineți true pentru a se începe cu "You" și a se sfârși cu "hello" și false pentru a începe sau a se sfâri cu "goodbye".

Provocare finalizată

Ați făcut ceva asemănător cu acestea?

string songLyrics = "You say goodbye, and I say hello";
Console.WriteLine(songLyrics.StartsWith("You"));
Console.WriteLine(songLyrics.StartsWith("goodbye"));

Console.WriteLine(songLyrics.EndsWith("hello"));
Console.WriteLine(songLyrics.EndsWith("goodbye"));

Felicitări!

Ați completat introducerea rapidă "Hello C#".

Puteți învăța mai multe despre lucrul cu string-uri în subiectul despre string-uri din Ghidul de programare C#. Sfaturi cum-să despre lucrul cu string-uri.

Tradus din această pagină oficială de documentație Microsoft.

[C#] Convertirea string în Color și invers

Aceste metode statice sunt folositoare, de exemplu, într-un program în care utilizatorul poate selecta o culoare care trebuie salvată ca o setare, de exemplu într-un fișier XML, și încărcată din acel fișier XML la următoarea pornire a programului. Metoda Color.ToString nu este suficientă uneori (de exemplu, în cazul în care șirul de caractere trebuie într-un alt format).

Metodele sunt puse într-o clasă statică Utils, care nu e pusă în întregime aici. Sunt marcate ca internal pentru a putea fi folosite din interiorul proiectului în care se află dar nu din afară.

Cod sursă

internal static string ColorToString(Color color)
{
    byte a = color.A,
        r = color.R,
        g = color.G,
        b = color.B;
    byte[] arr = new byte[] { a, r, g, b };
    string s = BitConverter.ToString(arr).Replace("-", "");
    return "#" + s;
}

internal static Color StringToColor(string str)
{
    int a = Int32.Parse(str.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
    int r = Int32.Parse(str.Substring(3, 2), System.Globalization.NumberStyles.HexNumber);
    int g = Int32.Parse(str.Substring(5, 2), System.Globalization.NumberStyles.HexNumber);
    int b = Int32.Parse(str.Substring(7, 2), System.Globalization.NumberStyles.HexNumber);

    return Color.FromArgb(a, r, g, b);
}

Capturi de ecran

Explicație

Color este un tip structură din domeniul (en. namespace) System.Drawing. Are proprietăție A (opacitatea, alfa), R (red, roșu), G (green, verde), B (blue, albastru). Aceste 4 proprietăți au tipul byte și stochează valori de la 0 la 255. Cu cât valoarea e mai mare, cu atât culoarea respectivă e mai intensă în culoarea afișată de structura Color respectivă, sau în cazul A culoarea devine mai puțin transparentă cu cât valoarea e mai mare, 255 însemnând opac complet.

Funcția ColorToString transformă culoarea color într-un string. Ea folosește metoda statică BitConverter.ToString pentru a transforma tabloul unidimensional de lungime 4, tip byte cu cele 4 proprietăți in ordinea de mai sus, pentru a obține un șir de caractere cu cele 4 proprietăți în baza 16. Apoi imediat se apelează Replace pentru a șterge caracterele „-” din șirul obținut. De exemplu, înainte de Replace valoarea este "F4-19-28-F1" și se șterg caracterele „-” apoi se pune un # în față, se obține valoarea returnată „#F41928F1”.

Funcția StringToColor primește un string din care se șterge primul caracter (#) și se iau rând pe rând 2 câte 2 caractere din el: din primele 2 se obține un int cu nr. transformat în baza 10 din baza 16, la fel din celelalte. Apoi se folosește metoda statică Color.FromArgb apelată cu cele 4 valori definitorii ale unei culori: a, r, g, b.

Cele 2 metode sunt inverse una alteia.

Dacă sunt folosite în producție, aceste metode trebuie făcute să intercepteze excepțiile posibile (try - catch - finally). Doar metoda StringToColor necesită modificări în acest caz:

internal static Color StringToColor(string str)
{
    try
    {
        int a = Int32.Parse(str.Substring(1, 2), System.Globalization.NumberStyles.HexNumber);
        int r = Int32.Parse(str.Substring(3, 2), System.Globalization.NumberStyles.HexNumber);
        int g = Int32.Parse(str.Substring(5, 2), System.Globalization.NumberStyles.HexNumber);
        int b = Int32.Parse(str.Substring(7, 2), System.Globalization.NumberStyles.HexNumber);

        return Color.FromArgb(a, r, g, b);
    }
    catch (Exception)
    {
        return Color.Empty;
    }
}



[C++, programare dinamică] Numărul de numere de N cifre cu produsul cifrelor 0

Dându-se N, scrieți un program care determină câte numere de N cifre cu produsul cifrelor 0 există.



·        N este numărul de cifre ale numerelor cerute



Fiindcă sunt în discuție numere în baza 10, rezultatul este întotdeauna 0 dacă produsul este mai mare decât 9N, 9 fiind cea mai mare cifră în baza 10. Pentru algoritmul naiv, folosit pentru verificare, este important că dacă un număr conține cel puțin o cifră 0 atunci produsul cifrelor sale este 0 și numărul de numere căutat crește cu 1.
Stabilirea formulei de recurență

Dacă notăm:

·        A[x] = câte numere de x cifre au produsul cifrelor 0, și

·        B[i] = câte numere de i cifre există



Cazurile de bază ale recurenței sunt:

·        A[0] = 0 (nu există nr. de 0 cifre)

·        A[1] = 1 (cazul numărului 0)

·        Mai rămâne cazul general A[x] = ?, tratat în continuare.



Pentru ca un număr să aibă x cifre, trebuie ca prima cifră să fie diferită de 0, deci pentru prima cifră există 9 posibilități (cazurile celor 10 cifre din baza 10, mai rămân 9 cifre dacă 0 se exclude). Din acest paragraf rezultă următoarele valori pentru B:



B[1] = nr. de nr. de 1 cifră posibile = 10,

               B[2] = 9 * 10 nr. de 2 cifre posibile,

               B[3] = 9 * 10 * 10 numere de 3 cifre posibile

etc.


Urmează exprimări ale A[x].

A[2] se calculează manual mai jos și rezultă din calcule valoarea 9 * 1.
Prima cifră nu poate fi 0 deci pentru prima cifră sunt în total 9 posibilități. A doua cifră poate și reprezintă o singură posibilitate. Cazurile sunt: 10, 20, ....., 90.

A[3] = 9 * 1 * 9 (nr. de 3 cifre cu a doua cifră 0 = 9 * câte numere de 1 cifră există, minus 1, adică fără 0)
               + 9 * 9 * 1 (nr. de 3 cifre cu a treia cifră 0 = 9 * câte numere de 1 cifră există, minus 1, adică fără 0))
+ 9 * 1 * 1 (nr. de 3 cifre cu a doua și a treia cifră 0)
= nr. de numere de 3 cifre cu cel puțin o cifră 0

Intuitiv dar incorect:
= 9 * (B[1] – 1) + 9 * (B[1] – 1) + A[2] (ce e bold = 9 sau A[2], se aduna la fiecare A[x] pe lângă A[x – 1] și altele, la sfârșitul sumei)

Din formula generala gasita mai tarziu, rezulta aceasta relatie pt A[3]:
                                             = 9 * A[2] + 9 * A[2] + 9

Apoi:

               B[4] = 9 * 10 * 10 * 10,
               Dintre care A[4] = 9 * 1 * 9 * 9 + 9 * 9 * 1 * 9 + 9 * 9 * 9 * 1 +
                                             9 * 1 * 1 * 9 + 9 * 9 * 1 * 1 + 9 * 1 * 9 * 1 +
                                             9 * 1 * 1 * 1 // o notație mai scurtă: 9199, 9919, 9991, 9119, 9911, 9191, 9111, ce e cu bold face împreună valoarea (9 * A[3]).
                                             = 9 * A[3][0] + 9*1*9*9 + 9*1*1*9 + 9*1*9*1 + 9 ( 9*1*1*1 ) =
A[4] = 9*(991+919+911) + 9*(99+91) + 9*(19) + 9*(11)
O exprimare incompletă dar care aduce înțelesuri noi:
                              A[4] = 9 * A[3] + 9 * A[3] / 9 (nr. de nr. de 3 cifre cu a doua cifră 0)

9 * A[3]: Cifra 1: 9 posibilități, cifra 2: 9 posibilități
9 * A[3] / 9: Cifra 1: 9 posibilități, cifra 2: 1 posibilitate (0),
    și prin împ. la 9 => Cifra 1: 1 posibilitate, cifra 2: 1 posibilitate,
    și prin înm. cu 9 se adaugă o cifră în față.


Împreună, cei doi termeni din expresia lui A[4] de mai sus însumează pt. a doua cifră 10 posibilități, câte sunt în general, dar în expresie, al doilea termen se împarte la 9 pentru ca posibilitățile din cifra 1 să devină 9/9 (9 împărțit din 9) din 9 adică 1. Astfel se tratează cazul când prima cifră e oricare poate fi în general (9 posibilități) și când prima cifră e oricare cifră din baza 10 (adică 10 posibilități).

Alte exprimări:
               = 9 * A[3] + 9 * (câte nr. de 2 cifre cu cifra unităților nenulă sunt) + 9 * (B[1] – 1) + 9
               = 9 * A[3] + 9 * (B[2] – 1) + 9 * (B[1] – 1) + 9.






Dintre care A[5] = 9 * A[4] + 9 * A[3] + 9 * A[2] + 9 * A[1] (am scos semnele de + și *, fiecare termen este sumă de produse de 9 și 1)

Încercare de a scrie formula generală: A[x] = A[x-1] + (A[x-2] – 1) + (A[x-3] – 1) + … + A[1] ;
Formula generală cu termeni crescători: A[x] = A[1] + … + (A[x-3] – 1) + (A[x-2] – 1) + A[x-1];

Verificare:
A[2] = 9 * A[1] + 0
A[3] = A[1] + A[2] = 9 * A[2] + 9 // (1) + (9*1)
A[4] = 9 * A[3] + 9
+ 9 * (nr. de 3 cifre cu cifra zecilor 0) + (nr. de 3 cifre cu cifra unităților 0) +
                                            
Având în vedere încercările de mai sus, mi-am dat seama este bine în produse să nu iau cele 10 posibilități de cifre direct, că e nevoie să iau 9 separat de unu-le care repr. cifra 0.


Exerciții:
A[2] = 91 = 9*A[1]
A[3] = 9*(91) + 9*(19) + 9*(11)
                              = 9*A[2] + 9*A[1] + 9
A[4] = 9*(991+919+911) + 9*(99+91) + 9*(19) + 9*(11)
                              = 9*A[3] + 9*(99 + A[2]) + 9*A[1] + 9
A[5] = 9*A[4][0] + 9*(999+991+919+911) + 9*(99+91) + 9*(9+1)
                              = 9*A[4] + 9*(999+A[3]) + 9*(99 + A[2]) + 9*A[1] + 9

Penultima încercare de a scrie o formulă de recurență corectă:
A[x] = 9 * A[x-1] + 9 * (_(x-2)cifreDe9_ + A[x-2])  +
               9 * (_(x-3)cifreDe9_ + A[x-3]) + … + 9*A[2] + 9

Exerciții:
A[1] = 1
A[2] = 9 * A[1]
A[3] = 9 * A[2] + 9 * A[2] + 9
               = 9*9 + 9 * 9 + 9= 81 +81+9
A[4] = 9 * A[3] + 9 * (99 + A[2]) + 9 * A[2] + 9
               = 9 * (A[3] + 9*9 + A[2] + A[2] + 1) =
               = 9 * (171 + 81 + 9 + 9 + 1) = 9(271) =  2439
A[5]= 9 * A[4] + 9 * (999 + A[3]) + 9 * (99 * A[2]) + 9 * A[2] + 9
               = 9 *(A[4] + 9*9*9 + A[3] + 9 * 9 + A[2] + A[2] + 1) =
               = 9 * ()

Formula finală:
A[x] = 9 * (A[x-1] + _(x-2)cifreDe9_ + A[x-2]  +
               _(x-3)cifreDe9_ + A[x-3] + … + A[2] + 1)

Codul sursă

#include <iostream>
#include <vector>
#include <fstream>
using namespace std;

/// Prin algoritm naiv, intoarce nr. de numere de
/// N cifre cu produsul cifrelor 0. pow10 si pow9N sunt
/// valori precalculate pentru optimizarea for-ului din
/// functia main().
long long int naiv(int N,
 long long int pow10[18],
 long long int pow9N)
{
 if (N == 0) return 0;

 long long int j = 0, prod, ii, i, start;
 if (N == 1) start = 0;
 else start = pow10[N - 1];

 for (i = start; i < pow10[N]; ++i)
 {
  if (i == 0)
  {
   ++j;
  }
  else
  {
   ii = i;
   while (ii)
   {
    if (ii % 10 == 0)
    {
     ++j;
     break;
    }
    ii /= 10;
   }
  }
 }

 return j;
}


// cate numere de N cifre se pot face sa aiba produsul cifrelor 0
long long int pd(long long int N, vector<long long int> &A)
{
 A[0] = 0;
 A[1] = 1;
 A[2] = 9;
 for (long long int i = 3; i <= N; ++i)
 {
  A[i] = 0;
  for (long long int j = 1; j <= i; ++j)
  {
   if (j == 1)
    A[i]++;
   else if (j == 2)
    A[i] += A[2];
   else if (j == 3)
   {
    if (i > 3)
    {
     A[i] += A[j - 1] +
      pow(9, j - 1);
    }
    else
    {
     A[i] += A[j - 1];
    }
   }
   else if (j >= 4)
   {
    if (j == i)
    {
     A[i] += A[j - 1];
    }
    else
    {
     A[i] += A[j - 1] +
      pow(9, j - 1);
    }
   }
  }
  A[i] *= 9;
 }

 return A[N];
}


int main()
{
 int N;

 cout << "Introduceti numarul de cifre: " << endl;
 cin >> N;

 vector<long long int> A(N + 1);
 // contine puteri ale lui 10 pt. calcul mai rapid in algoritmul naiv
 long long int pow10[] = {
  1,
  10,
  100,
  1000,
  10000,
  100000,
  1000000,
  10000000,
  100000000,
  1000000000,
  10000000000,
  100000000000,
  1000000000000,
  10000000000000,
  100000000000000,
  1000000000000000,
  10000000000000000,
  100000000000000000,
  1000000000000000000,
  10000000000000000000
 };

 long long int pow9N = pow(9, N);
 ofstream out("Text.txt");
 long long int rezultat = pd(N, A);
 // compara rezultatele alg. naiv cu cel de pd.
 for (int i = 0; i <= N; ++i)
 {
  long long int rn = naiv(i, pow10, pow9N);
  out << "A[" << i << "] = " <<
   A[i] << " (pd)\t\t|\t\t" << rn <<
   " (naiv)\t\t|\t\t" <<
   (rn == A[i] ? "CORECT" : "___GRESIT") << endl;
 }
 out.close();

 cout << "Rezultatele au fost afisate in fisier." << endl;
 return 0;
}

Capturi de ecran




Ieșire

O parte din ce afiseaza programul in fisier:

A[0] = 0 (pd)  |  0 (naiv)  |  CORECT
A[1] = 1 (pd)  |  1 (naiv)  |  CORECT
A[2] = 9 (pd)  |  9 (naiv)  |  CORECT
A[3] = 171 (pd)  |  171 (naiv)  |  CORECT
A[4] = 2439 (pd)  |  2439 (naiv)  |  CORECT
A[5] = 30951 (pd)  |  30951 (naiv)  |  CORECT
A[6] = 368559 (pd)  |  368559 (naiv)  |  CORECT
A[7] = 4217031 (pd)  |  4217031 (naiv)  |  CORECT
A[8] = 46953279 (pd)  |  46953279 (naiv)  |  CORECT
A[9] = 512579511 (pd)  |  512579511 (naiv)  |  CORECT
A[10] = 5513215599 (pd)  |  5513215599 (naiv)  |  CORECT